Tanzu Application Platform 1.1 をminikubeにインストールします。
本記事ではTAPのFulll ProfileをminikubeにLocal Registryを使ってInstallし、"Hello World"なアプリケーションをソースコードからテストとスキャンを経てデプロイする機能("Source Test Scan to URL")を試します。 。
なお、Iterate Profileをインストールするメモはこちら。
目次
- minikubeクラスタの作成
- Local Registryのインストール
- Cluster Essentials for VMware Tanzuのインストール
- Tanzu Application Platformのインストール
- Workloadのデプロイ
minikubeクラスタの作成
CPUは8、メモリは16GBでminikubeクラスタを作成します。
minikube start --memory=16384 --cpus=8 --disk-size=70GB --kubernetes-version='1.22.10' --driver='hyperkit'
Local Registryのインストール
minikubeのregistry addonだとPersistent Volumeがattachされておらず、minikube stop
するとデータが失われるので、
カスタマイズした次のマニフェストを使います。
cat <<EOF | kubectl apply -f-
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: kube-registry
namespace: kube-system
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 30Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
kubernetes.io/minikube-addons: registry
name: registry
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
actual-registry: "true"
strategy:
type: Recreate
template:
metadata:
labels:
actual-registry: "true"
kubernetes.io/minikube-addons: registry
spec:
containers:
- image: registry:2.7.1@sha256:d5459fcb27aecc752520df4b492b08358a1912fcdfa454f7d2101d4b09991daa
imagePullPolicy: IfNotPresent
name: registry
ports:
- containerPort: 5000
protocol: TCP
env:
- name: REGISTRY_STORAGE_DELETE_ENABLED
value: "true"
- name: REGISTRY_VALIDATION_DISABLED
value: "true"
- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
value: /var/lib/registry
volumeMounts:
- name: image-store
mountPath: /var/lib/registry
volumes:
- name: image-store
persistentVolumeClaim:
claimName: kube-registry
---
apiVersion: v1
kind: Service
metadata:
labels:
kubernetes.io/minikube-addons: registry
name: registry
namespace: kube-system
spec:
type: ClusterIP
ports:
- port: 80
name: http
targetPort: 5000
- port: 443
name: https
targetPort: 443
selector:
actual-registry: "true"
kubernetes.io/minikube-addons: registry
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: registry-proxy
namespace: kube-system
spec:
selector:
matchLabels:
registry-proxy: "true"
template:
metadata:
labels:
registry-proxy: "true"
kubernetes.io/minikube-addons: registry
spec:
containers:
- image: gcr.io/google_containers/kube-registry-proxy:0.4@sha256:1040f25a5273de0d72c54865a8efd47e3292de9fb8e5353e3fa76736b854f2da
imagePullPolicy: IfNotPresent
name: registry-proxy
ports:
- name: registry
containerPort: 80
hostPort: 5000
env:
- name: REGISTRY_HOST
value: registry.kube-system.svc.cluster.local
- name: REGISTRY_PORT
value: "80"
EOF
minikubeのdockerがregistry serviceのDNS名を解決できるように、Node上の/etc/hosts
にregistry serviceのClusterIPを明示します。
echo "$(kubectl get svc -n kube-system registry -ojsonpath='{.spec.clusterIP}')\tregistry.kube-system.svc.cluster.local" | minikube ssh --native-ssh=false "sudo tee -a /etc/hosts"
Cluster Essentials for VMware Tanzuのインストール
TAPのインストールに必要なKapp ControllerとSecretgen Controllerをデプロイするために Cluster Essentials for VMware Tanzu をインストールします。
# Mac
pivnet download-product-files --product-slug='tanzu-cluster-essentials' --release-version='1.1.0' --product-file-id=1191985
# Linux
pivnet download-product-files --product-slug='tanzu-cluster-essentials' --release-version='1.1.0' --product-file-id=1191987
# Windows
pivnet download-product-files --product-slug='tanzu-cluster-essentials' --release-version='1.1.0' --product-file-id=1191983
Cluster Essentialsのimgpkg bundleをlocal registryにrelocateします。
まずはTanzuNet Registryにログインします。
TANZUNET_USERNAME=...
TANZUNET_PASSWORD=...
docker login registry.tanzu.vmware.com -u ${TANZUNET_USERNAME} -p ${TANZUNET_PASSWORD}
Cluster Essentialsのimgpkg bundleをtarファイルに保存します。
imgpkg copy -b registry.tanzu.vmware.com/tanzu-cluster-essentials/cluster-essentials-bundle:1.1.0 --to-tar ~/cluster-essentials-bundle-1.1.0.tar
localhost:5000でregistryにアクセスできるようにport-forwardします。
kubectl port-forward --namespace kube-system service/registry 5000:80
tarファイルのimgpkg bundleをlocalhost:5000にrelocateします。
imgpkg copy --tar ~/cluster-essentials-bundle-1.1.0.tar --to-repo localhost:5000/tanzu-cluster-essentials/cluster-essentials-bundle
relocateしたimgpkg bundleを使ってCluster Essentialsをインストールします。
mkdir tanzu-cluster-essentials
tar xzvf tanzu-cluster-essentials-*-amd64-1.1.0.tgz -C tanzu-cluster-essentials
cd tanzu-cluster-essentials
export INSTALL_REGISTRY_HOSTNAME=localhost:5000
export INSTALL_REGISTRY_USERNAME=admin
export INSTALL_REGISTRY_PASSWORD=admin
export INSTALL_BUNDLE=${INSTALL_REGISTRY_HOSTNAME}/tanzu-cluster-essentials/cluster-essentials-bundle:1.1.0
./install.sh --yes
cd ..
Tanzu Application Platformのインストール
TAP用Package Repositoryの登録
TAPのimgpkg bundleをtarファイルに保存します。 約16GBあるのでかなり時間がかかります。
👆 tarファイルを経由せずに直接registryにcopyすることもできますが、
失敗したときにダウンロードからやり直しになってしまうので、
試行錯誤を見越してtarでダウンロードしておいた方が効率的です。
TAP_VERSION=1.1.1
imgpkg copy -b registry.tanzu.vmware.com/tanzu-application-platform/tap-packages:${TAP_VERSION} --to-tar ~/tap-${TAP_VERSION}.tar
tarファイルのimgpkg bundleをlocalhost:5000にrelocateします。
imgpkg copy --tar ~/tap-${TAP_VERSION}.tar --to-repo localhost:5000/tanzu-application-platform/tap-packages
Package Repositoryの設定をします。kapp controllerがlocalhost:5000にアクセスできなかったので、ホスト名にはregistry.kube-system.svc.cluster.localを使用します。
kubectl create ns tap-install
tanzu secret registry add tap-registry \
--username "${INSTALL_REGISTRY_USERNAME}" \
--password "${INSTALL_REGISTRY_PASSWORD}" \
--server registry.kube-system.svc.cluster.local \
--export-to-all-namespaces \
--yes \
--namespace tap-install
tanzu package repository add tanzu-tap-repository \
--url registry.kube-system.svc.cluster.local/tanzu-application-platform/tap-packages:${TAP_VERSION} \
--namespace tap-install
Full Profileのインストール
TAPをインストールするためのtap-values.yml
を作成します。
cnrs.domain_name
には仮のドメインを指定します。あとでenvoyのExternal IPが設定されてから変更します。
ℹ️ grype packageはこのタイミングではインストールせず、
excluded_packages
に加えて除外します。
TAP 1.1ではgrype packageはnamespaceごとに必要です。
profileのインストールでは、1つのnamespaceにしかgrype packageがインストールされず中途半端なので、それを除外して後に個別でインストールします。
cat <<EOF > tap-values.yml
profile: full
ceip_policy_disclosed: true
cnrs:
domain_name: tap.example.com
domain_template: "{{.Name}}-{{.Namespace}}.{{.Domain}}"
default_tls_secret: tanzu-system-ingress/cnrs-default-tls
provider: local
buildservice:
kp_default_repository: registry.kube-system.svc.cluster.local/build-service
kp_default_repository_username: admin
kp_default_repository_password: admin
tanzunet_username: ${TANZUNET_USERNAME}
tanzunet_password: ${TANZUNET_PASSWORD}
enable_automatic_dependency_updates: true
supply_chain: testing_scanning
ootb_supply_chain_testing_scanning:
registry:
server: registry.kube-system.svc.cluster.local
repository: supplychain
contour:
envoy:
service:
type: LoadBalancer
externalTrafficPolicy: Local
learningcenter:
ingressDomain: learningcenter.tap.example.com
ingressSecret:
secretName: learningcenter-tls
tap_gui:
ingressEnabled: true
ingressDomain: tap.example.com
service_type: ClusterIP
tls:
secretName: cnrs-default-tls
namespace: tanzu-system-ingress
app_config:
app:
baseUrl: https://tap-gui.tap.example.com
backend:
baseUrl: https://tap-gui.tap.example.com
cors:
origin: https://tap-gui.tap.example.com
catalog:
locations:
- type: url
target: https://github.com/sample-accelerators/tanzu-java-web-app/blob/main/catalog/catalog-info.yaml
- type: url
target: https://github.com/sample-accelerators/spring-petclinic/blob/accelerator/catalog/catalog-info.yaml
- type: url
target: https://github.com/tanzu-japan/spring-music/blob/tanzu/catalog/catalog-info.yaml
accelerator:
domain: tap.example.com
ingress:
include: true
enable_tls: true
tls:
secret_name: cnrs-default-tls
namespace: tanzu-system-ingress
server:
service_type: ClusterIP
metadata_store:
app_service_type: ClusterIP
ingress_enabled: "true"
ingress_domain: tap.example.com
package_overlays:
- name: cnrs
secrets:
- name: cnrs-default-tls
- name: learningcenter
secrets:
- name: learningcenter-certificate
- name: metadata-store
secrets:
- name: metadata-store-ingress-tls
excluded_packages:
- grype.scanning.apps.tanzu.vmware.com
EOF
Cloud Native Runtimesで使用するデフォルトのTLS証明書を用意するための次の定義をoverlayで作成します。以下のドキュメントを参考にしました。
- https://docs.vmware.com/en/Cloud-Native-Runtimes-for-VMware-Tanzu/1.1/tanzu-cloud-native-runtimes-1-1/GUID-external_dns.html
- https://knative.dev/docs/serving/using-a-tls-cert/#manually-adding-a-tls-certificate
cat <<EOF > cnrs-default-tls.yml
#@ load("@ytt:data", "data")
#@ load("@ytt:overlay", "overlay")
#@ namespace = data.values.ingress.external.namespace
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: cnrs-selfsigned-issuer
namespace: #@ namespace
spec:
selfSigned: { }
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cnrs-ca
namespace: #@ namespace
spec:
commonName: cnrs-ca
isCA: true
issuerRef:
kind: Issuer
name: cnrs-selfsigned-issuer
secretName: cnrs-ca
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: cnrs-ca-issuer
namespace: #@ namespace
spec:
ca:
secretName: cnrs-ca
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cnrs-default-tls
namespace: #@ namespace
spec:
dnsNames:
- #@ "*.{}".format(data.values.domain_name)
issuerRef:
kind: Issuer
name: cnrs-ca-issuer
secretName: cnrs-default-tls
---
apiVersion: projectcontour.io/v1
kind: TLSCertificateDelegation
metadata:
name: contour-delegation
namespace: #@ namespace
spec:
delegations:
- secretName: cnrs-default-tls
targetNamespaces:
- "*"
#@overlay/match by=overlay.subset({"metadata":{"name":"config-network"}, "kind": "ConfigMap"})
---
data:
#@overlay/match missing_ok=True
default-external-scheme: https
EOF
Cloud Native RuntimesからKnative Serving以外のリソースを削除するoverlayを作成します。 Learning CenterにTLS証明書の
cat <<EOF > learningcenter-certificate.yml
#@ load("@ytt:data", "data")
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: learningcenter-selfsigned-issuer
namespace: #@ data.values.namespace
spec:
selfSigned: { }
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: learningcenter-ca
namespace: #@ data.values.namespace
spec:
commonName: learningcenter-ca
isCA: true
issuerRef:
kind: Issuer
name: learningcenter-selfsigned-issuer
secretName: learningcenter-ca
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: learningcenter-ca-issuer
namespace: #@ data.values.namespace
spec:
ca:
secretName: learningcenter-ca
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: learningcenter-tls
namespace: #@ data.values.namespace
spec:
dnsNames:
- #@ data.values.ingressDomain
- #@ "*.{}".format(data.values.ingressDomain)
issuerRef:
kind: Issuer
name: learningcenter-ca-issuer
secretName: learningcenter-tls
EOF
Metadata StoreにCloud Native RuntimesのデフォルトのTLS証明書を使うoverlayを作成します。
ℹ️ Learning Centerと違ってMetadata StoreはContourのHTTPProxyを使用しているため、
TLSCertificateDelegationでCloud Native Runtimes用のTLS証明書を使えます。
Learning CenterはIngressを使っているため、TAP 1.1に含まれるContour 1.18.2ではTLSCertificateDelegationは使えません。
Contour 1.20からIngresでもTLSCertificateDelegationが使えるようになります。
cat <<EOF > metadata-store-ingress-tls.yml
#@ load("@ytt:overlay", "overlay")
#@overlay/match by=overlay.subset({"metadata":{"name":"metadata-store-ingress"}, "kind": "HTTPProxy"})
---
spec:
virtualhost:
tls:
secretName: tanzu-system-ingress/cnrs-default-tls
#@overlay/match by=overlay.subset({"metadata":{"name":"ingress-cert"}, "kind": "Certificate"})
#@overlay/remove
---
EOF
overlayファイルをSecretとして作成します。
kubectl -n tap-install create secret generic cnrs-default-tls \
-o yaml \
--dry-run=client \
--from-file=cnrs-default-tls.yml \
| kubectl apply -f-
kubectl -n tap-install create secret generic learningcenter-certificate \
-o yaml \
--dry-run=client \
--from-file=learningcenter-certificate.yml \
| kubectl apply -f-
kubectl -n tap-install create secret generic metadata-store-ingress-tls \
-o yaml \
--dry-run=client \
--from-file=metadata-store-ingress-tls.yml \
| kubectl apply -f-
LoadBalancer Serviceを作成できるように別のコンソールでminikube tunnel
を実行しておきます。
minikube tunnel
TAPをインストールします。
tanzu package install tap -p tap.tanzu.vmware.com -v ${TAP_VERSION} --values-file tap-values.yml -n tap-install
インストールの進捗は次のコマンドで確認します。
watch kubectl get app -n tap-install
全てのappが Reconcile succeeded
になるまで待ちます。
$ kubectl get app -n tap-install
NAME DESCRIPTION SINCE-DEPLOY AGE
appliveview-conventions Reconcile succeeded 10m 11m
buildservice Reconcile succeeded 17m 17m
cartographer Reconcile succeeded 19s 12m
cert-manager Reconcile succeeded 68s 17m
cnrs Reconcile succeeded 10m 11m
contour Reconcile succeeded 3m9s 12m
conventions-controller Reconcile succeeded 12m 12m
developer-conventions Reconcile succeeded 10m 11m
fluxcd-source-controller Reconcile succeeded 18s 17m
ootb-delivery-basic Reconcile succeeded 4s 10m
ootb-supply-chain-basic Reconcile succeeded 2s 10m
ootb-templates Reconcile succeeded 18s 11m
service-bindings Reconcile succeeded 10m 17m
services-toolkit Reconcile succeeded 19s 17m
source-controller Reconcile succeeded 28s 17m
spring-boot-conventions Reconcile succeeded 10m 11m
tap Reconcile succeeded 3m3s 18m
tap-auth Reconcile succeeded 7m50s 17m
tap-telemetry Reconcile succeeded 25s 17m
tekton-pipelines Reconcile succeeded 25s 17m
インストールされたパッケージは次の通りです。
$ kubectl get packageinstall -n tap-install
NAME PACKAGE NAME PACKAGE VERSION DESCRIPTION AGE
accelerator accelerator.apps.tanzu.vmware.com 1.1.2 Reconcile succeeded 15m
api-portal api-portal.tanzu.vmware.com 1.0.15 Reconcile succeeded 17m
appliveview backend.appliveview.tanzu.vmware.com 1.1.1 Reconcile succeeded 15m
appliveview-connector connector.appliveview.tanzu.vmware.com 1.1.1 Reconcile succeeded 17m
appliveview-conventions conventions.appliveview.tanzu.vmware.com 1.1.1 Reconcile succeeded 15m
buildservice buildservice.tanzu.vmware.com 1.5.1 Reconcile succeeded 17m
cartographer cartographer.tanzu.vmware.com 0.3.0 Reconcile succeeded 16m
cert-manager cert-manager.tanzu.vmware.com 1.5.3+tap.2 Reconcile succeeded 17m
cnrs cnrs.tanzu.vmware.com 1.2.0 Reconcile succeeded 15m
contour contour.tanzu.vmware.com 1.18.2+tap.2 Reconcile succeeded 16m
conventions-controller controller.conventions.apps.tanzu.vmware.com 0.6.3 Reconcile succeeded 16m
developer-conventions developer-conventions.tanzu.vmware.com 0.6.0 Reconcile succeeded 15m
fluxcd-source-controller fluxcd.source.controller.tanzu.vmware.com 0.16.4 Reconcile succeeded 17m
image-policy-webhook image-policy-webhook.signing.apps.tanzu.vmware.com 1.1.2 Reconcile succeeded 16m
learningcenter learningcenter.tanzu.vmware.com 0.2.0 Reconcile succeeded 15m
learningcenter-workshops workshops.learningcenter.tanzu.vmware.com 0.2.0 Reconcile succeeded 12m
metadata-store metadata-store.apps.tanzu.vmware.com 1.1.3 Reconcile succeeded 16m
ootb-delivery-basic ootb-delivery-basic.tanzu.vmware.com 0.7.1 Reconcile succeeded 15m
ootb-supply-chain-testing-scanning ootb-supply-chain-testing-scanning.tanzu.vmware.com 0.7.1 Reconcile succeeded 15m
ootb-templates ootb-templates.tanzu.vmware.com 0.7.1 Reconcile succeeded 15m
scanning scanning.apps.tanzu.vmware.com 1.1.1 Reconcile succeeded 17m
service-bindings service-bindings.labs.vmware.com 0.7.1 Reconcile succeeded 17m
services-toolkit services-toolkit.tanzu.vmware.com 0.6.0 Reconcile succeeded 17m
source-controller controller.source.apps.tanzu.vmware.com 0.3.3 Reconcile succeeded 17m
spring-boot-conventions spring-boot-conventions.tanzu.vmware.com 0.4.0 Reconcile succeeded 15m
tap tap.tanzu.vmware.com 1.1.1 Reconcile succeeded 17m
tap-auth tap-auth.tanzu.vmware.com 1.0.1 Reconcile succeeded 17m
tap-gui tap-gui.tanzu.vmware.com 1.1.1 Reconcile succeeded 15m
tap-telemetry tap-telemetry.tanzu.vmware.com 0.1.4 Reconcile succeeded 17m
tekton-pipelines tekton.tanzu.vmware.com 0.33.5 Reconcile succeeded 17m
Envoyに設定されたExternal IPを使って、cnrs.domain_name
を変更します。ドメイン名にはsslip.ioを使用します。
例えば、External IPが10.105.146.158の場合に、cnrs.domain_name
に*.10-105-146-158.sslip.ioを指定します。
次のコマンドでtap-values.yml
を更新します。
sed -i.bak "s|tap.example.com|$(kubectl get -n tanzu-system-ingress svc envoy -ojsonpath='{.status.loadBalancer.ingress[0].ip}' | sed 's/\./-/g').sslip.io|g" tap-values.yml
TAPを更新します。
tanzu package installed update tap -n tap-install -v ${TAP_VERSION} -f tap-values.yml
Default TLSのCertificateのDNS名が更新されたことを確認してください。
$ kubectl get certificate -n tanzu-system-ingress cnrs-default-tls -ojsonpath='{.spec.dnsNames[0]}'
*.10-105-146-158.sslip.io
$ kubectl get certificate -n learningcenter learningcenter-tls -ojsonpath='{.spec.dnsNames[0]}'
learningcenter.10-105-146-158.sslip.io
👆 sslip.ioにアクセスできない環境の場合は、
ラップトップ上の/etc/hosts
に今後使用する127.0.0.1 <...>.tap.example.com
を一つずつ設定してください。
Workloadのデプロイ
Workloadを作成するための事前準備
RBACの設定
https://docs.vmware.com/en/Tanzu-Application-Platform/1.1/tap/GUID-install-components.html#setup (一部変更しています)
kubectl create ns demo
tanzu secret registry add registry-credentials --server registry.kube-system.svc.cluster.local --username admin --password admin --namespace demo
cat <<EOF | kubectl -n demo apply -f -
apiVersion: v1
kind: Secret
metadata:
name: tap-registry
annotations:
secretgen.carvel.dev/image-pull-secret: ""
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: e30K
---
apiVersion: v1
kind: Secret
metadata:
name: git-ssh
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
secrets:
- name: registry-credentials
- name: git-ssh
imagePullSecrets:
- name: registry-credentials
- name: tap-registry
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: default-permit-deliverable
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: deliverable
subjects:
- kind: ServiceAccount
name: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: default-permit-workload
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: workload
subjects:
- kind: ServiceAccount
name: default
EOF
Tekton Pipelineの作成
今回はテストは空実装にします。
cat <<'EOF' | kubectl -n demo apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: developer-defined-tekton-pipeline
labels:
apps.tanzu.vmware.com/pipeline: test
spec:
params:
- name: source-url
- name: source-revision
tasks:
- name: test
params:
- name: source-url
value: $(params.source-url)
- name: source-revision
value: $(params.source-revision)
taskSpec:
params:
- name: source-url
- name: source-revision
steps:
- name: test
image: alpine
script: |-
echo "Skip Test :)"
EOF
ScanTemplateのインストール
ScanTemplateをdemo namespaceに作成するために、grype packageをここでインストールします。
cat <<EOF > grype-demo.yaml
namespace: demo
targetImagePullSecret: registry-credentials
EOF
tanzu package install grype-demo -p grype.scanning.apps.tanzu.vmware.com -v 1.1.1 -n tap-install -f grype-demo.yaml
$ kubectl get scantemplate -n demo
NAME AGE
blob-source-scan-template 27s
private-image-scan-template 27s
public-image-scan-template 27s
public-source-scan-template 27s
ScanPolicyの作成
ScanPolicyはサンプルと同じものを使用します。
cat <<'EOF' | kubectl -n demo apply -f -
apiVersion: scanning.apps.tanzu.vmware.com/v1beta1
kind: ScanPolicy
metadata:
name: scan-policy
spec:
regoFile: |
package policies
default isCompliant = false
# Accepted Values: "Critical", "High", "Medium", "Low", "Negligible", "UnknownSeverity"
violatingSeverities := ["Critical","High","UnknownSeverity"]
ignoreCVEs := []
contains(array, elem) = true {
array[_] = elem
} else = false { true }
isSafe(match) {
fails := contains(violatingSeverities, match.Ratings.Rating[_].Severity)
not fails
}
isSafe(match) {
ignore := contains(ignoreCVEs, match.Id)
ignore
}
isCompliant = isSafe(input.currentVulnerability)
EOF
ここまでnamespace単位で行う必要のある設定でした。
Node.jsアプリのデプロイ
tanzu apps workload apply hello \
--app hello \
--git-repo https://github.com/making/hello-nodejs \
--git-branch master \
--type web \
--label apps.tanzu.vmware.com/has-tests=true \
--annotation autoscaling.knative.dev/minScale=1 \
-n demo \
-y
tanzu apps workload tail hello -n demo
作成されるリソースを確認したければ次のコマンドをwatchしてください。
watch kubectl get pod,gitrepo,pipelinerun,sourcescan,imgs,build,imagescan,podintent,taskrun,imagerepository,app,ksvc,certificate,httpproxy -n demo -owide
ソースコードの脆弱性スキャンで"Failed"になります。
$ kubectl get sourcescans -n demo hello
NAME PHASE SCANNEDREVISION SCANNEDREPOSITORY AGE CRITICAL HIGH MEDIUM LOW UNKNOWN CVETOTAL
hello Failed 19610d1789fb30d571e0b27a65ed03a7bdec2922 http://source-controller.flux-system.svc.cluster.local./gitrepository/demo/hello/19610d1789fb30d571e0b27a65ed03a7bdec2922.tar.gz 3m15s 0 1 0 1 0 2
スキャン結果を確認するためにtanzu insight
コマンドを使用します。
このコマンドを使用するための設定を行います。
read-onlyなアクセストークンを作成するために次のSecretを作成します。
cat <<EOF | kubectl apply -f-
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metadata-store-ready-only
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metadata-store-read-only
subjects:
- kind: ServiceAccount
name: metadata-store-read-client
namespace: metadata-store
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: metadata-store-read-client
namespace: metadata-store
automountServiceAccountToken: false
---
apiVersion: v1
kind: Secret
metadata:
name: metadata-store-read-only-token
namespace: metadata-store
annotations:
kubernetes.io/service-account.name: metadata-store-read-client
type: kubernetes.io/service-account-token
EOF
アクセストークンを取得して、Metadata Storeのエンドポイントを設定します。 https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.1/tap/GUID-scst-store-using-encryption-and-connection.html
kubectl get secret -n tanzu-system-ingress cnrs-default-tls -otemplate='{{(index .data "ca.crt") | base64decode}}' > cnrs-default-tls.ca
METADATA_STORE_DOMAIN=$(kubectl get httpproxy -n metadata-store metadata-store-ingress -ojsonpath='{.spec.virtualhost.fqdn}')
AUTH_TOKEN=$(kubectl get secret -n metadata-store metadata-store-read-only-token -otemplate='{{.data.token | base64decode}}')
tanzu insight config set-target https://${METADATA_STORE_DOMAIN} --ca-cert cnrs-default-tls.ca --access-token=${AUTH_TOKEN}
以下のログが出力されます。
ℹ Using config file: /Users/toshiaki/.config/tanzu/insight/config.yaml
ℹ Setting trustedcacert in config
ℹ Setting accesstoken in config
ℹ Setting endpoint in config to: https://metadata-store.10-105-146-158.sslip.io
✔ Success: Set Metadata Store endpoint
次のコマンドで疎通チェックします。
$ tanzu insight health
Success: Reached Metadata Store!
tanzu insight
コマンドが使えるようになりました。
tanzu insight source
でソースコードスキャンの結果を確認します。
$ tanzu insight source get --org making --repo hello-nodejs --commit 19610d1789fb30d571e0b27a65ed03a7bdec2922
1. ID: 1
Repository: hello-nodejs
Commit: 19610d1789fb30d571e0b27a65ed03a7bdec2922
Organization: making
Packages:
1. accepts@1.3.8
...
8. cookie@0.5.0
CVEs:
1. CVE-2017-18589 (High)
1. CVE-2017-18589 (Unknown)
1. CVE-2017-18589 (Unknown)
9. cookie-signature@1.0.6
...
20. fresh@0.5.2
CVEs:
1. CVE-2013-1779 (Low)
1. CVE-2013-1779 (Unknown)
21. function-bind@1.1.1
...
56. vary@1.1.2
CVE-2017-18589がHigh Severityで報告されています。
ℹ️ SBOMの出力結果はscanしたPodのログで確認できます。
$ kubectl logs -n demo scan-hello-<...> <?xml version="1.0" encoding="UTF-8"?> <bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:v="http://cyclonedx.org/schema/ext/vulnerability/1.0" version="1" serialNumber="urn:uuid:916fdfd5-2c29-4bc4-9dbf-a11c9731c5f1"> <metadata> <timestamp>2022-06-21T17:07:18Z</timestamp> <tools> <tool> <vendor>anchore</vendor> <name>grype</name> <version>v0.33.1</version> </tool> </tools> <component type="file"> <name>https://github.com/making/hello-nodejs</name> <version>19610d1789fb30d571e0b27a65ed03a7bdec2922</version> </component> </metadata> <components> <component type="library"> <name>accepts</name> <version>1.3.8</version> </component> <!-- ... --> <component type="library"> <name>content-type</name> <version>1.0.4</version> </component> <component type="library"> <name>cookie</name> <version>0.5.0</version> <v:vulnerabilities> <v:vulnerability ref="urn:uuid:a13b50a9-6348-4f67-b703-87fa33b7017d"> <v:id>CVE-2017-18589</v:id> <v:source name="nvd"> <v:url>http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-18589</v:url> </v:source> <v:ratings> <v:rating> <v:severity>High</v:severity> </v:rating> <v:rating> <v:score> <v:base>5</v:base> <v:impact>2.9</v:impact> <v:exploitability>10</v:exploitability> </v:score> <v:method>CVSSv2</v:method> <v:vector>AV:N/AC:L/Au:N/C:N/I:N/A:P</v:vector> </v:rating> <v:rating> <v:score> <v:base>7.5</v:base> <v:impact>3.6</v:impact> <v:exploitability>3.9</v:exploitability> </v:score> <v:method>CVSSv3</v:method> <v:vector>CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H</v:vector> </v:rating> </v:ratings> <v:description>An issue was discovered in the cookie crate before 0.7.6 for Rust. Large integers in the Max-Age of a cookie cause a panic.</v:description> <v:advisories> <v:advisory>https://rustsec.org/advisories/RUSTSEC-2017-0005.html</v:advisory> </v:advisories> </v:vulnerability> </v:vulnerabilities> </component> <component type="library"> <name>cookie-signature</name> <version>1.0.6</version> </component> <!-- ... --> <component type="library"> <name>forwarded</name> <version>0.2.0</version> </component> <component type="library"> <name>fresh</name> <version>0.5.2</version> <v:vulnerabilities> <v:vulnerability ref="urn:uuid:17c0acd2-cb25-4dce-af74-3a15c416c3fd"> <v:id>CVE-2013-1779</v:id> <v:source name="nvd"> <v:url>http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1779</v:url> </v:source> <v:ratings> <v:rating> <v:severity>Low</v:severity> </v:rating> <v:rating> <v:score> <v:base>2.1</v:base> <v:impact>2.9</v:impact> <v:exploitability>3.9</v:exploitability> </v:score> <v:method>CVSSv2</v:method> <v:vector>AV:N/AC:H/Au:S/C:N/I:P/A:N</v:vector> </v:rating> </v:ratings> <v:description>Cross-site scripting (XSS) vulnerability in the 3 slide gallery in the Fresh theme before 7.x-1.4 for Drupal allows remote authenticated users with the administer themes permission to inject arbitrary web script or HTML via unspecified vectors.</v:description> <v:advisories> <v:advisory>http://drupalcode.org/project/fresh.git/commitdiff/08a3ccb</v:advisory> <v:advisory>http://www.openwall.com/lists/oss-security/2013/02/28/3</v:advisory> <v:advisory>http://drupal.org/node/1929482</v:advisory> <v:advisory>http://drupal.org/node/1723316</v:advisory> </v:advisories> </v:vulnerability> </v:vulnerabilities> </component> <component type="library"> <name>function-bind</name> <version>1.1.1</version> </component> <!-- ... --> <component type="library"> <name>vary</name> <version>1.1.2</version> </component> </components> </bom>
https://github.com/anchore/anchore-engine/issues/304 を見る限り、この脆弱性はRustのライブラリに関するものであり、
今回使用しているのはNode.jsのライブラリなので、これは誤検出です。
ignoreCVEs
にCVE-2017-18589を追加して、ScanPolicyを更新します。
cat <<'EOF' | kubectl -n demo apply -f -
apiVersion: scanning.apps.tanzu.vmware.com/v1beta1
kind: ScanPolicy
metadata:
name: scan-policy
spec:
regoFile: |
package policies
default isCompliant = false
# Accepted Values: "Critical", "High", "Medium", "Low", "Negligible", "UnknownSeverity"
violatingSeverities := ["Critical","High","UnknownSeverity"]
# https://github.com/anchore/anchore-engine/issues/304
ignoreCVEs := ["CVE-2017-18589"]
contains(array, elem) = true {
array[_] = elem
} else = false { true }
isSafe(match) {
fails := contains(violatingSeverities, match.Ratings.Rating[_].Severity)
not fails
}
isSafe(match) {
ignore := contains(ignoreCVEs, match.Id)
ignore
}
isCompliant = isSafe(input.currentVulnerability)
EOF
Scanが再度走ります。今度は"Completed"になります。
$ kubectl get sourcescans -n demo hello
NAME PHASE SCANNEDREVISION SCANNEDREPOSITORY AGE CRITICAL HIGH MEDIUM LOW UNKNOWN CVETOTAL
hello Completed 19610d1789fb30d571e0b27a65ed03a7bdec2922 http://source-controller.flux-system.svc.cluster.local./gitrepository/demo/hello/19610d1789fb30d571e0b27a65ed03a7bdec2922.tar.gz 13m 0 1 0 1 0 2
ちなみにIgnoreしたCVEもMetaData Storeに残り、CVE情報でソースを検索するとhello-nodejsがヒットします。
$ tanzu insight vulnerabilities sources --cveid CVE-2017-18589
1. ID: 1
Repository: hello-nodejs
Commit: 19610d1789fb30d571e0b27a65ed03a7bdec2922
Organization: making
Packages:
1. cookie@0.5.0
CVEs:
1. CVE-2017-18589 (High)
1. CVE-2017-18589 (Unknown)
1. CVE-2017-18589 (Unknown)
さて、ソースコードスキャンが成功した後、イメージのビルドが行われ、次のイメージの脆弱性をスキャンします。
イメージの脆弱性スキャンで"Failed"になります。
$ kubectl get imagescan -n demo hello
NAME PHASE SCANNEDIMAGE AGE CRITICAL HIGH MEDIUM LOW UNKNOWN CVETOTAL
hello Failed registry.kube-system.svc.cluster.local/supplychain/hello-demo@sha256:a1a401c25e787cb380eec4433b9ba1de4b7742352e8c80ce57c60110d6e69b5b 79s 0 7 3 12 0 22
tanzu insight image
でイメージスキャンの結果を確認します。
$ tanzu insight image get --digest sha256:a1a401c25e787cb380eec4433b9ba1de4b7742352e8c80ce57c60110d6e69b5b
ID: 1
Registry: registry.kube-system.svc.cluster.local
Image Name: supplychain/hello-demo
Digest: sha256:a1a401c25e787cb380eec4433b9ba1de4b7742352e8c80ce57c60110d6e69b5b
Packages:
1. accepts@1.3.8
...
8. cookie@0.5.0
CVEs:
1. CVE-2017-18589 (High)
1. CVE-2017-18589 (Unknown)
1. CVE-2017-18589 (Unknown)
9. cookie-signature@1.0.6
...
20. fresh@0.5.2
CVEs:
1. CVE-2013-1779 (Low)
1. CVE-2013-1779 (Unknown)
21. function-bind@1.1.1
...
67. coreutils@8.28-1ubuntu1
CVEs:
1. CVE-2016-2781 (Low)
68. dash@0.5.8-2.10
...
76. gcc-8-base@8.4.0-1ubuntu1~18.04
CVEs:
1. CVE-2020-13844 (Medium)
77. gpgv@2.2.4-1ubuntu1.5
...
89. libc-bin@2.27-3ubuntu1.6
CVEs:
1. CVE-2009-5155 (Low)
2. CVE-2015-8985 (Low)
3. CVE-2016-20013 (Low)
90. libc6@2.27-3ubuntu1.6
CVEs:
1. CVE-2009-5155 (Low)
2. CVE-2015-8985 (Low)
3. CVE-2016-20013 (Low)
91. libcap-ng0@0.7.7-3.1
...
98. libgcc1@1:8.4.0-1ubuntu1~18.04
CVEs:
1. CVE-2020-13844 (Medium)
99. libgcrypt20@1.8.1-4ubuntu1.3
100. libgmp10@2:6.1.2+dfsg-2
101. libgnutls30@3.5.18-1ubuntu1.5
CVEs:
1. CVE-2018-16868 (Low)
102. libgpg-error0@1.27-6
...
108. libncurses5@6.1-1ubuntu1.18.04
CVEs:
1. CVE-2019-17594 (Low)
2. CVE-2019-17595 (Low)
3. CVE-2021-39537 (Low)
4. CVE-2022-29458 (Low)
109. libncursesw5@6.1-1ubuntu1.18.04
CVEs:
1. CVE-2019-17594 (Low)
2. CVE-2019-17595 (Low)
3. CVE-2021-39537 (Low)
4. CVE-2022-29458 (Low)
110. libnettle6@3.4.1-0ubuntu0.18.04.1
...
116. libpcre3@2:8.39-9ubuntu0.1
CVEs:
1. CVE-2017-11164 (Low)
117. libprocps6@2:3.3.12-3ubuntu1.2
...
126. libstdc++6@8.4.0-1ubuntu1~18.04
CVEs:
1. CVE-2020-13844 (Medium)
127. libsystemd0@237-3ubuntu10.53
128. libtasn1-6@4.13-2
129. libtinfo5@6.1-1ubuntu1.18.04
CVEs:
1. CVE-2019-17594 (Low)
2. CVE-2019-17595 (Low)
3. CVE-2021-39537 (Low)
4. CVE-2022-29458 (Low)
130. libudev1@237-3ubuntu10.53
...
135. locales@2.27-3ubuntu1.6
CVEs:
1. CVE-2009-5155 (Low)
2. CVE-2015-8985 (Low)
3. CVE-2016-20013 (Low)
136. login@1:4.5-1ubuntu2.2
CVEs:
1. CVE-2013-4235 (Low)
137. lsb-base@9.20170808ubuntu1
...
140. ncurses-base@6.1-1ubuntu1.18.04
CVEs:
1. CVE-2019-17594 (Low)
2. CVE-2019-17595 (Low)
3. CVE-2021-39537 (Low)
4. CVE-2022-29458 (Low)
141. ncurses-bin@6.1-1ubuntu1.18.04
CVEs:
1. CVE-2019-17594 (Low)
2. CVE-2019-17595 (Low)
3. CVE-2021-39537 (Low)
4. CVE-2022-29458 (Low)
142. netbase@5.4
143. openssl@1.1.1-1ubuntu2.1~18.04.17
144. passwd@1:4.5-1ubuntu2.2
CVEs:
1. CVE-2013-4235 (Low)
145. perl-base@5.26.1-6ubuntu0.5
CVEs:
1. CVE-2020-16156 (Medium)
146. procps@2:3.3.12-3ubuntu1.2
...
179. ansi-regex@3.0.0
CVEs:
1. CVE-2021-3807 (High)
1. CVE-2021-3807 (Unknown)
1. CVE-2021-3807 (Unknown)
2. GHSA-93q8-gq69-wqmw (High)
180. ansi-regex@5.0.0
CVEs:
1. CVE-2021-3807 (High)
1. CVE-2021-3807 (Unknown)
1. CVE-2021-3807 (Unknown)
2. GHSA-93q8-gq69-wqmw (High)
181. ansi-regex@5.0.1
...
324. once@1.4.0
325. opener@1.5.2
CVEs:
1. CVE-2021-27478 (High)
1. CVE-2021-27478 (Unknown)
1. CVE-2021-27478 (Unknown)
2. CVE-2021-27482 (High)
2. CVE-2021-27482 (Unknown)
2. CVE-2021-27482 (Unknown)
3. CVE-2021-27498 (High)
3. CVE-2021-27498 (Unknown)
3. CVE-2021-27498 (Unknown)
4. CVE-2021-27500 (High)
4. CVE-2021-27500 (Unknown)
4. CVE-2021-27500 (Unknown)
326. p-map@4.0.0
...
382. yallist@4.0.0
たくさん検出されました。
Metadata StoreにはSBOMの情報が保存されますが、CVEとSeverityの情報しかわからないので、
grype
CLIを直接使ってFixedされたCVEの情報を取得します。
SCAN_IMAGE=$(kubectl get scantemplate -n demo private-image-scan-template -ojsonpath='{.spec.template.containers[0].image}')
TARGET_IMAGE=$(kubectl get imgs -n demo hello -ojsonpath='{.status.latestImage}')
kubectl run grype -n demo --restart=Never -ti --image=${SCAN_IMAGE} --timeout=10m --rm --command -- grype -v ${TARGET_IMAGE} --only-fixed
If you don't see a command prompt, try pressing enter.
[0000] INFO New version of grype is available: 0.40.0
[0001] INFO downloading new vulnerability DB
[0015] INFO identified distro: Ubuntu 18.04.6 LTS from-lib=syft
[0015] INFO cataloging image from-lib=syft
[0119] INFO updated vulnerability DB to version=3 built="2022-06-23 08:15:59 +0000 UTC"
[0120] INFO ignoring 46 matches due to user-provided ignore rules
NAME INSTALLED FIXED-IN VULNERABILITY SEVERITY
ansi-regex 3.0.0 3.0.1 GHSA-93q8-gq69-wqmw High
ansi-regex 5.0.0 5.0.1 GHSA-93q8-gq69-wqmw High
npm 8.5.0 8.11.0 GHSA-hj9c-8jmm-8c52 Medium
FixedでSeverityがHigh以上なものだけを見るとGHSA-93q8-gq69-wqmwが該当します。
どこで使われているのかを確認するために、次のコマンドでイメージを展開し、ansi-regex
を検索します。
$ imgpkg pull -i $(kubectl get imgs -n demo hello -ojsonpath='{.status.latestImage}' | sed 's/registry.kube-system.svc.cluster.local/localhost:5000/g') -o /tmp/hello
$ cd /tmp/hello
$ grep -irI ansi-regex ./
./layers/tanzu-buildpacks_node-engine-lite/node/lib/node_modules/npm/docs/content/commands/npm-install.md: npm install ansi-regex --save-bundle
...
./layers/tanzu-buildpacks_node-engine-lite/node/lib/node_modules/npm/node_modules/ansi-regex/package.json: "repository": "chalk/ansi-regex",
どうやら、node自身にバンドルされているライブラリのようです。この脆弱性をFixするにはnode-engine buildpackが更新される必要があります。
とはいえ、脆弱性のPoCを見るとアプリがansi-regexを使ってるansiRegex().test(...)
で悪意のある文字列を受け取らない問題なさそう。
アプリではansi-regexは使用していないのでこれはignoreします。(buildpack teamに確認中です)
UnfixedなCVEもいったんignoreします。
というわけで
- CVE-2021-3807
- GHSA-93q8-gq69-wqmw
- CVE-2021-27478
- CVE-2021-27482
- CVE-2021-27498
- CVE-2021-27500
を
ignoreCVEs
に追加して、ScanPolicyを更新します。
cat <<'EOF' | kubectl -n demo apply -f -
apiVersion: scanning.apps.tanzu.vmware.com/v1beta1
kind: ScanPolicy
metadata:
name: scan-policy
spec:
regoFile: |
package policies
default isCompliant = false
# Accepted Values: "Critical", "High", "Medium", "Low", "Negligible", "UnknownSeverity"
violatingSeverities := ["Critical","High","UnknownSeverity"]
# https://github.com/anchore/anchore-engine/issues/304
ignoreCVEs := ["CVE-2017-18589", "CVE-2021-3807", "GHSA-93q8-gq69-wqmw", "CVE-2021-27478", "CVE-2021-27482", "CVE-2021-27498", "CVE-2021-27500"]
contains(array, elem) = true {
array[_] = elem
} else = false { true }
isSafe(match) {
fails := contains(violatingSeverities, match.Ratings.Rating[_].Severity)
not fails
}
isSafe(match) {
ignore := contains(ignoreCVEs, match.Id)
ignore
}
isCompliant = isSafe(input.currentVulnerability)
EOF
Scanが再度走ります。今度は"Completed"になります。
$ kubectl get imagescan -n demo hello
NAME PHASE SCANNEDIMAGE AGE CRITICAL HIGH MEDIUM LOW UNKNOWN CVETOTAL
hello Completed registry.kube-system.svc.cluster.local/supplychain/hello-demo@sha256:a1a401c25e787cb380eec4433b9ba1de4b7742352e8c80ce57c60110d6e69b5b 7m55s 0 7 3 12 0 22
無視したCVEもMetaData Storeに規則され、次のように指定した脆弱性を持つイメージの検索結果に含まれます。
$ tanzu insight vulnerabilities images --cveid CVE-2021-3807
1. ID: 1
Registry: registry.kube-system.svc.cluster.local
Image Name: supplychain/hello-demo
Digest: sha256:a1a401c25e787cb380eec4433b9ba1de4b7742352e8c80ce57c60110d6e69b5b
Packages:
1. ansi-regex@3.0.0
CVEs:
1. CVE-2021-3807 (High)
1. CVE-2021-3807 (Unknown)
1. CVE-2021-3807 (Unknown)
2. GHSA-93q8-gq69-wqmw (High)
2. ansi-regex@5.0.0
CVEs:
1. CVE-2021-3807 (High)
1. CVE-2021-3807 (Unknown)
1. CVE-2021-3807 (Unknown)
2. GHSA-93q8-gq69-wqmw (High)
Scanをパスしたので、ようやくアプリのデプロイが行われます。
$ tanzu apps workload get -n demo hello
# hello: Ready
---
lastTransitionTime: "2022-06-22T18:07:27Z"
message: ""
reason: Ready
status: "True"
type: Ready
Pods
NAME STATUS RESTARTS AGE
hello-00001-deployment-994f5755f-f2rjc Running 0 37s
hello-build-1-build-pod Succeeded 0 9m52s
hello-config-writer-v4v9w-pod Succeeded 0 96s
hello-sq9wx-test-pod Succeeded 0 13m
scan-hello-24ggg-8wp7h Succeeded 0 10m
scan-hello-72g2f-hmf2g Succeeded 0 9m16s
scan-hello-j5pfr-pm4hj Succeeded 0 13m
scan-hello-q9ctb-hqbfg Succeeded 0 2m45s
scan-hello-w8svx-m7tx5 Succeeded 0 2m45s
Knative Services
NAME READY URL
hello Ready https://hello-demo.10-105-146-158.sslip.io
$ curl -k https://hello-demo.10-105-146-158.sslip.io
Hello Tanzu!!
確認が終わればWorkloadを削除します。
tanzu apps workload delete -n demo hello -y