Mirantis Secure Registry 3 (MSR)をk0sで動かそう #k0s #msr #k8s #kubernetes #mirantis
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
Mirantis Secure Registryとは、DockerコンテナイメージやHelm Chartを安全に保管・共有・管理できるプライベートレジストリです。2021年末にリリースされたバージョン3.0.0にて、従来より統合されていたMirantis Kubernetes Engineから独立し、標準的なKubernetes上で動作可能となりました。
本稿ではMirantis Secure Registry (以下MSR)バージョン3.0.0を、ワンバイナリで動作する軽量なフル機能Kubernetesディストリビューションであるk0sにデプロイしてみます。
なお、本稿ではMSRの詳細な設定手順や利用方法は省略します。公式ドキュメントを参照いただくか、今後予定されているMirantis社公認トレーニングの開催をお待ちください。
Vagrantfile
VirtualboxとVagrantで仮想マシンを1台作成し、そちらにk0sとMSRをインストールします。
base_install =<<-SHELL timedatectl set-timezone Asia/Tokyo yum install -y ntp systemctl enable ntpd systemctl start ntpd SHELL Vagrant.configure("2") do |config| config.vm.box = "centos/7" config.vm.box_check_update = false config.vm.define "node1" do |cf| cf.vm.hostname = "node1" cf.vm.network "private_network", ip: "192.168.56.101" cf.vm.provision "shell", inline: base_install cf.vm.provider "virtualbox" do |vb| vb.memory = 12288 vb.cpus = 4 end end end
k0s自体は軽量ですが、MSRのセキュリティスキャンを利用する場合はパワフルな環境が必要であるためメモリ12GB・4vCPUと設定しています。当初はメモリ4GB・1vCPUでしたが正常に動作せず、次にメモリ8GB・2vCPUと倍にしても動作に支障が見られたためです。詳細はSystem requirementsを参照してください。
k0sインストール
Virtualbox/Vagrantでのk0sインストールについての詳細は過去記事「k0sでKubernetesをVirtualbox/Vagrantにインストールしてみよう」をご覧ください。以降では手順をかいつまんで記述します。
k0sは本稿執筆時点で最新の v1.23.1+k0s.0 を利用します。
[vagrant@node1 ~]$ /usr/local/bin/k0s version v1.23.1+k0s.0
デフォルトのインストール設定ファイルにて、IPアドレスを変更します。
[vagrant@node1 ~]$ k0s config create > k0s.yaml.orig [vagrant@node1 ~]$ cp -a k0s.yaml.orig k0s.yaml [vagrant@node1 ~]$ vi k0s.yaml [vagrant@node1 ~]$ sudo mkdir /etc/k0s [vagrant@node1 ~]$ sudo mv k0s.yaml /etc/k0s/
[vagrant@node1 ~]$ diff -u k0s.yaml.orig /etc/k0s/k0s.yaml --- k0s.yaml.orig 2022-01-04 15:08:14.826736210 +0900 +++ /etc/k0s/k0s.yaml 2022-01-04 15:10:39.865766191 +0900 @@ -5,11 +5,10 @@ name: k0s spec: api: - address: 10.0.2.15 + address: 192.168.56.101 k0sApiPort: 9443 port: 6443 sans: - - 10.0.2.15 - 192.168.56.101 - fe80::5054:ff:fe4d:77d3 - fe80::a00:27ff:fefc:8421 @@ -81,7 +80,7 @@ scheduler: {} storage: etcd: - peerAddress: 10.0.2.15 + peerAddress: 192.168.56.101 type: etcd telemetry: enabled: true
シングルノードでインストールします。k0sは、デフォルトではコントローラノードでワークロードを動作できないようになっていますが、 --single オプションを付与してシングルノードインストールを行うと、コントローラノードがワーカーノードを兼用し、1ノードでKubernetesを起動できるようになります。
[vagrant@node1 ~]$ sudo /usr/local/bin/k0s install controller -c /etc/k0s/k0s.yaml --single --kubelet-extra-args "--node-ip=192.168.56.101" [vagrant@node1 ~]$ sudo /usr/local/bin/k0s start [vagrant@node1 ~]$ sudo /usr/local/bin/k0s status Version: v1.23.1+k0s.0 Process ID: 3862 Role: controller Workloads: true SingleNode: true
Roleが「controller」でありつつ、Workloadsも「true」となっていることがわかります。kubectl get nodesでも見てみましょう。
[vagrant@node1 ~]$ mkdir .kube [vagrant@node1 ~]$ sudo cp /var/lib/k0s/pki/admin.conf .kube/config [vagrant@node1 ~]$ sudo chown $USER:$USER .kube/config [vagrant@node1 ~]$ chmod 600 .kube/config [vagrant@node1 ~]$ export KUBECONFIG=~/.kube/config [vagrant@node1 ~]$ k0s kubectl get nodes NAME STATUS ROLES AGE VERSION node1 Ready control-plane 82s v1.23.1+k0s
デフォルトのk0sインストールなら「No resources found」となってしまいますが、シングルノードインストールであればコントローラノードもワークロードを動作可能であるため、このような結果となります。
以上でk0sによるKubernetesのインストールは完了です。
Helmインストール
MSRバージョン3と関連ソフトウェアはHelmでインストールするようになっているので、まずHelmをインストールしましょう。本稿執筆時点で最新のv3.7.2を使用します。
[vagrant@node1 ~]$ curl -LO https://get.helm.sh/helm-v3.7.2-linux-amd64.tar.gz -LO https://get.helm.sh/helm-v3.7.2-linux-amd64.tar.gz.sha256sum [vagrant@node1 ~]$ sha256sum -c helm-v3.7.2-linux-amd64.tar.gz.sha256sum helm-v3.7.2-linux-amd64.tar.gz: OK [vagrant@node1 ~]$ tar xf helm-v3.7.2-linux-amd64.tar.gz [vagrant@node1 ~]$ sudo mv linux-amd64/helm /usr/local/bin/ [vagrant@node1 ~]$ helm version version.BuildInfo{Version:"v3.7.2", GitCommit:"663a896f4a815053445eec4153677ddc24a0a361", GitTreeState:"clean", GoVersion:"go1.16.10"}
以上でHelmのインストールは完了です。
ボリュームの準備
MSRバージョン3では永続データの格納用に、3つのボリュームを使用します。PrerequisitesではPersistent Volume (PV)の動的プロビジョニングを要求していますが、本稿は1ノードであり内容を単純化するために、hostPathの静的PVを準備・利用することとします。
まず、脆弱性スキャンデータ用ボリュームのディレクトリを作成し、所有者・所属グループを 101:103 で設定しておきます。ボリューム用ディレクトリは割り当ての際に自動的に作成されるのですが、所有者・所属グループが root:root となり書き込みできずエラーとなるため、あらかじめ作成・設定しています。この他、イメージデータ用・レポジトリメタデータ用の2ディレクトリは自動作成・設定される root:root で問題ないため、ここでは作成しません。
[vagrant@node1 ~]$ sudo mkdir -p /vols/msr-scanningstore [vagrant@node1 ~]$ sudo chown 101:103 /vols/msr-scanningstore [vagrant@node1 ~]$ ls -ld /vols/msr-scanningstore drwxr-xr-x. 2 101 103 6 Jan 4 15:58 /vols/msr-scanningstore
次のYAMLマニフェストでPVを作成します。
apiVersion: v1 kind: PersistentVolume metadata: name: msr-hostpath spec: accessModes: - ReadWriteMany capacity: storage: 20Gi hostPath: path: /vols/msr
apiVersion: v1 kind: PersistentVolume metadata: name: rethinkdb-cluster-hostpath spec: accessModes: - ReadWriteOnce capacity: storage: 1Gi hostPath: path: /vols/msr-rethinkdb-cluster
apiVersion: v1 kind: PersistentVolume metadata: name: scanningstore-hostpath spec: accessModes: - ReadWriteOnce capacity: storage: 24Gi hostPath: path: /vols/msr-scanningstore
各PVのspec.accessModes、access.capacity.storageは、MSRのHelm Chart内で指定されている値を用いています。Recommended system requirementsにImage data storageは25〜100GB推奨とあるので msr-hostpathは20Giでは足りない可能性があります。必要であれば適宜変更してください。
では、PVを作成します。
[vagrant@node1 ~]$ k0s kubectl apply -f static-pv.yaml persistentvolume/msr-hostpath created persistentvolume/rethinkdb-cluster-hostpath created persistentvolume/scanningstore-hostpath created [vagrant@node1 ~]$ k0s kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE msr-hostpath 20Gi RWX Retain Available 21s rethinkdb-cluster-hostpath 1Gi RWO Retain Available 21s scanningstore-hostpath 24Gi RWO Retain Available 21s
作成できました。
関連ソフトウェアのインストール
Prerequisitesでは、関連ソフトウェアとしてcert-managerとPostgres Operatorのインストールが求められているので、手順に従って実施します。
cert-manager
[vagrant@node1 ~]$ k0s kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.yaml customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created namespace/cert-manager created serviceaccount/cert-manager-cainjector created serviceaccount/cert-manager created serviceaccount/cert-manager-webhook created clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector created clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers created clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates created clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders created clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges created clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created clusterrole.rbac.authorization.k8s.io/cert-manager-view created clusterrole.rbac.authorization.k8s.io/cert-manager-edit created clusterrole.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created role.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created role.rbac.authorization.k8s.io/cert-manager:leaderelection created role.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created rolebinding.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created rolebinding.rbac.authorization.k8s.io/cert-manager:leaderelection created rolebinding.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created service/cert-manager created service/cert-manager-webhook created deployment.apps/cert-manager-cainjector created deployment.apps/cert-manager created deployment.apps/cert-manager-webhook created mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created [vagrant@node1 ~]$ k0s kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.crds.yaml customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io configured customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io configured customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io configured customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io configured customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io configured customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io configured
cert-managerネームスペースを確認し、各オブジェクトが問題ないことを確認します。
[vagrant@node1 ~]$ k0s kubectl -n cert-manager get all NAME READY STATUS RESTARTS AGE pod/cert-manager-748f4d667d-7s7xk 1/1 Running 0 79s pod/cert-manager-cainjector-6cd5988f45-n7f5d 1/1 Running 0 79s pod/cert-manager-webhook-7498ddfd98-l78p2 1/1 Running 0 79s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/cert-manager ClusterIP 10.107.197.71 9402/TCP 79s service/cert-manager-webhook ClusterIP 10.105.218.129 443/TCP 79s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/cert-manager 1/1 1 1 79s deployment.apps/cert-manager-cainjector 1/1 1 1 79s deployment.apps/cert-manager-webhook 1/1 1 1 79s NAME DESIRED CURRENT READY AGE replicaset.apps/cert-manager-748f4d667d 1 1 1 79s replicaset.apps/cert-manager-cainjector-6cd5988f45 1 1 1 79s replicaset.apps/cert-manager-webhook-7498ddfd98 1 1 1 79s
Postgres Operator
[vagrant@node1 ~]$ helm repo add postgres-operator https://opensource.zalando.com/postgres-operator/charts/postgres-operator/ "postgres-operator" has been added to your repositories [vagrant@node1 ~]$ helm repo up Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "postgres-operator" chart repository Update Complete. Happy Helming! [vagrant@node1 ~]$ helm install postgres-operator postgres-operator/postgres-operator \ --set configKubernetes.spilo_runasuser=101 \ --set configKubernetes.spilo_runasgroup=103 \ --set configKubernetes.spilo_fsgroup=103 manifest_sorter.go:192: info: skipping unknown hook: "crd-install" manifest_sorter.go:192: info: skipping unknown hook: "crd-install" manifest_sorter.go:192: info: skipping unknown hook: "crd-install" NAME: postgres-operator LAST DEPLOYED: Tue Jan 4 16:07:15 2022 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: To verify that postgres-operator has started, run: kubectl --namespace=default get pods -l "app.kubernetes.io/name=postgres-operator"
最後に表示されたコマンドを実行して、問題がないことを確認します。
[vagrant@node1 ~]$ k0s kubectl --namespace=default get pods -l "app.kubernetes.io/name=postgres-operator" NAME READY STATUS RESTARTS AGE postgres-operator-867bf8f978-tw4f9 1/1 Running 0 35s
MSRバージョン3のインストール
では、MSRバージョン3のインストールを行いましょう。
デフォルトではMSRのWebUIがClusterIPサービスで内部公開されるようになっているので、NodePortサービスで外部公開するように変更します。
また、ここではライセンスファイル「license.lic」を与えていますが、インストール後にライセンスファイルを適用することもできます。なお、以前のMSRと異なり、ライセンスファイルをWebUIからアップロードするのではなく、Helmコマンドで適用するようになっています。
[vagrant@node1 ~]$ helm install msr msr \ --repo https://registry.mirantis.com/charts/msr/msr \ --version 1.0.0 \ --set-file license=license.lic \ --set service.type=NodePort NAME: msr LAST DEPLOYED: Tue Jan 4 16:24:04 2022 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Release Notes: http://docs.mirantis.com/msr-3.0-01 1. Get the application URL by running these commands: export NODE_PORT=$(kubectl get --namespace default -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}' services msr) export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") echo https://$NODE_IP:$NODE_PORT 2. Run MSR CLI commands as follows: kubectl -n default exec -it deploy/msr-api -- msr <command></command> 3. Modifying rethinkdb.cluster.replicaCount requires additional steps to scale the MSR and eNZi databases (table replicas): AFTER increasing replicaCount, run the command: kubectl -n default exec -it deploy/msr-api -- msr db scale BEFORE decreasing replicaCount: - Decommission RethinkDB servers from highest to lowest: - Get a list of servers to decommission: kubectl -n default exec -it deploy/msr-api -- msr rethinkdb list - Decommission servers with: kubectl -n default exec -it deploy/msr-api -- msr rethinkdb decommission - Scale the database: kubectl -n default exec -it deploy/msr-api -- msr db scale
もし「timed out waiting for the condition」エラーとなってしまったら、しばらく待ってから「helm status msr」を実行してください。同じような使用方法のドキュメントが表示されるはずです。されない場合はその他の問題が発生している可能性がありますので、Podのログなどを確認してみてください。
よくあるパターンとしては必要なPVがうまく準備できていない場合などです。例えば脆弱性スキャンデータ用ボリュームのディレクトリの所有者・所属グループが root:root となっていて書き込みができないと、msr-scanningstore-0 Podのログが次のようになっています。
[vagrant@node1 ~]$ k0s kubectl logs msr-scanningstore-0 mkdir: cannot create directory ‘/home/postgres/pgdata/pgroot’: Permission denied mkdir: cannot create directory ‘/home/postgres/pgdata/pgroot’: Permission denied touch: cannot touch '/home/postgres/pgdata/pgroot/pg_log/postgresql-0.csv': No such file or directory (略)
MSRのWebUIへのアクセス
MSRのWebUIにアクセスするためのURLは、デプロイ成功時に表示されたコマンドで得ることができます。ただし、本稿では素のkubectlではなくk0s同梱のものを使っているため、kubectlの前にk0sを付与する必要があります。
[vagrant@node1 ~]$ export NODE_PORT=$(k0s kubectl get --namespace default -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}' services msr) [vagrant@node1 ~]$ export NODE_IP=$(k0s kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") [vagrant@node1 ~]$ echo https://$NODE_IP:$NODE_PORT https://192.168.56.101:30211
こちらにウェブブラウザでアクセスしてみましょう。
管理者のIDは「admin」、パスワードは「password」となっています。これらはMSRのHelm Chart内で指定されているので、興味のある方はHelm Chartを取得して調べてみてください。
脆弱性スキャンの有効化
管理者としてログインできたら、まずは脆弱性スキャンを有効にしてみましょう。左のサイドバーから System を開き、上の Security タブを開きます。Enable Scanning をトグルし、Sync Database now ボタンをクリックします。脆弱性スキャン用のデータベース初期化が始まります。メモリ12GB・4vCPUですが、30分以上かかりましたので気長に待ちましょう。
ユーザ、オーガニゼーション、チームの作成
MSRにはユーザ、オーガニゼーション、チームという概念があり、細かな権限設定やユーザのグルーピングを行えるようになっています。
ここではすべてをまとめるオーガニゼーションとして「creationline」があり、「dev」と「ops」の2チームが所属しており、「dev」チームには「alice」ユーザが、「ops」チームには「bob」ユーザが所属しているとします。
さらに「creationline」オーガニゼーションはプライベートなコンテナイメージレポジトリとして「logstash」を持っており、このレポジトリに対して「dev」チームは読み書き権限を持ち、「ops」チームは読み込み専用権限を持っているとします。
箇条書きでまとめると次のようになります。
- オーガニゼーション: creationline
- レポジトリ: logstash
- チーム: dev
- creationline/logstash レポジトリに R/W 権限を持つ
- ユーザ alice が所属
- チーム: ops
- creationline/logstash レポジトリに R/O 権限を持つ
- ユーザ bob が所属
MSRのレポジトリにDockerコンテナイメージをプッシュ・プル
MSRの creationline/logstash レポジトリにイメージをプッシュしてみましょう。MSRをインストールした仮想マシンではなく、ホスト側で実施していきます。
まず事前準備として、MSR (192.168.56.101:30211) をDockerデーモンに信頼させます。/etc/docker/daemon.json に insecure-registries キーを追加し、Dockerデーモンを再起動します。
{ "insecure-registries": [ "192.168.56.101:30211" ] }
% sudo systemctl restart docker
これを行わないと、docker login実施時に「Error response from daemon: Get "https://192.168.56.101:30211/v2/": x509: certificate is valid for 127.0.0.1, ::1, not 192.168.56.101」というエラーとなってしまうので忘れずに実施しましょう。
ではaliceユーザでMSRにログインします。
% docker login 192.168.56.101:30211 Username: alice Password: Login Succeeded
ログインできました。
elastic/logstash:7.13.3 イメージをMSRにプッシュしてみましょう。
% docker image tag elastic/logstash:7.13.3 192.168.56.101:30211/creationline/logstash:7.13.3 % docker image push 192.168.56.101:30211/creationline/logstash:7.13.3 The push refers to repository [192.168.56.101:30211/creationline/logstash] 752595536bdb: Pushed d83131943e63: Pushed 3865b0219f35: Pushed 2d7bcb60ab83: Pushed 8939b09a3291: Pushed c49f4b89350d: Pushed 9a543ee7f3be: Pushed 25709602f08b: Pushed 627247ba7b32: Pushed c646254d9f2f: Pushed 174f56854903: Pushed 7.13.3: digest: sha256:a24e6faa2337f4deaa903eb9036f01387414252d3f6649f0bfe471b897310c63 size: 2823
プッシュ成功しました。WebUIでも確認してみましょう。
このようにGUIで確認することが可能です。VulnerabilitiesがPendingとなっているのは脆弱性スキャン中という意味です。完了まで少々時間がかかるので、他のことをして待ちましょう。
aliceはcreationline/logstashに書き込み権限がありましたが、読み込み専用権限のbobではどうでしょうか。まずaliceはログアウトし、bobでログインし直します。
% docker logout 192.168.56.101:30211 Removing login credentials for 192.168.56.101:30211 % docker login 192.168.56.101:30211 Username: bob Password: Login Succeeded
次に elastic/logstash:7.16.2 をプッシュしてみます。
% docker image tag elastic/logstash:7.16.2 192.168.56.101:30211/creationline/logstash:7.16.2 % docker image push 192.168.56.101:30211/creationline/logstash:7.16.2 The push refers to repository [192.168.56.101:30211/creationline/logstash] e4cc9a5205b5: Preparing 22cadb4a5d42: Preparing 046452805d26: Preparing a9d36c36d24e: Preparing 4800551e926b: Preparing 0fc8b3a8b4d0: Waiting 15b6bb42d46c: Waiting ae62b93394a2: Waiting efb4c1e5fa42: Waiting 409c69e46596: Waiting 174f56854903: Waiting denied: requested access to the resource is denied
想定通り、書き込み権限のないbobではプッシュができませんでした。一方、読み込み権限はあるのでプルは可能です。
% docker image rm 192.168.56.101:30211/creationline/logstash:7.13.3 Untagged: 192.168.56.101:30211/creationline/logstash:7.13.3 Untagged: 192.168.56.101:30211/creationline/logstash@sha256:a24e6faa2337f4deaa903eb9036f01387414252d3f6649f0bfe471b897310c63 % docker image rm elastic/logstash:7.13.3 Untagged: elastic/logstash:7.13.3 Untagged: elastic/logstash@sha256:9cc4f59ac3b393bd503d6d8da3700433868d42ffd3f311c348eb32df0c253f04 Deleted: sha256:289a765558773dc7dd973c3d04680c0d0ceddafc2584034ad02473460d7342dd Deleted: sha256:45cec05d815e103ec7ba60b0eb474609e8473539be5923edf7e87b5bfe18a612 Deleted: sha256:3c713164fa71c59dafe691e6a46400bc73f661169c59ccfc5098cdd082188a9c Deleted: sha256:5c34fc522aa05f888841ea414476fcd6720fc487c6b48b18abdc07b37356e4eb Deleted: sha256:56da02333067501293ef10bbf8bc5372ff688517f3e033a4698202bddbbae281 Deleted: sha256:dd7f5008374c9cc9352db5a678281473e09e4d4353d7648b5621e1b3de43b80c Deleted: sha256:6e788512c81251cc71dbb7c1bb5ccaa3dc68ed6dd54df53645ad41c3e431558e Deleted: sha256:4b8fd99c44be485efecea68c665517b4c201b5dd994b4a73b060cc5bb8b409c7 Deleted: sha256:01771379ef4293584918fe3e7ac03cd9914f9340b9bf4ecc16e73f7bcb96a32b Deleted: sha256:0e5d2b96638ea2d7a72eb2a4bbed989d4b51e669ec762789c990a81df92e7025 Deleted: sha256:ef3bce480b0f7489a66c12559f64f6155c7031261d58e6dda91f438aa7a79969 Deleted: sha256:5b0b92f3990e2772d58c559c866d08436febf471792ad8502fce1f6ef568449e % docker image pull 192.168.56.101:30211/creationline/logstash:7.13.3 7.13.3: Pulling from creationline/logstash 2d473b07cdd5: Already exists f653a67c9318: Pull complete e9bd4c4e6834: Pull complete f7098d0fdf1a: Pull complete d3c2fac25849: Pull complete 3910b894cabf: Pull complete e264eba4146d: Pull complete f2690d75a5da: Pull complete a974cf3861bb: Pull complete 4931f440d283: Pull complete 79ac8791bae4: Pull complete Digest: sha256:a24e6faa2337f4deaa903eb9036f01387414252d3f6649f0bfe471b897310c63 Status: Downloaded newer image for 192.168.56.101:30211/creationline/logstash:7.13.3 192.168.56.101:30211/creationline/logstash:7.13.3
ついでにbobもログアウトして、匿名ユーザとしてMSRからプルを試みてみましょう。
% docker logout 192.168.56.101:30211 Removing login credentials for 192.168.56.101:30211 % docker image rm 192.168.56.101:30211/creationline/logstash:7.13.3 Untagged: 192.168.56.101:30211/creationline/logstash:7.13.3 Untagged: 192.168.56.101:30211/creationline/logstash@sha256:a24e6faa2337f4deaa903eb9036f01387414252d3f6649f0bfe471b897310c63 Deleted: sha256:289a765558773dc7dd973c3d04680c0d0ceddafc2584034ad02473460d7342dd Deleted: sha256:45cec05d815e103ec7ba60b0eb474609e8473539be5923edf7e87b5bfe18a612 Deleted: sha256:3c713164fa71c59dafe691e6a46400bc73f661169c59ccfc5098cdd082188a9c Deleted: sha256:5c34fc522aa05f888841ea414476fcd6720fc487c6b48b18abdc07b37356e4eb Deleted: sha256:56da02333067501293ef10bbf8bc5372ff688517f3e033a4698202bddbbae281 Deleted: sha256:dd7f5008374c9cc9352db5a678281473e09e4d4353d7648b5621e1b3de43b80c Deleted: sha256:6e788512c81251cc71dbb7c1bb5ccaa3dc68ed6dd54df53645ad41c3e431558e Deleted: sha256:4b8fd99c44be485efecea68c665517b4c201b5dd994b4a73b060cc5bb8b409c7 Deleted: sha256:01771379ef4293584918fe3e7ac03cd9914f9340b9bf4ecc16e73f7bcb96a32b Deleted: sha256:0e5d2b96638ea2d7a72eb2a4bbed989d4b51e669ec762789c990a81df92e7025 Deleted: sha256:ef3bce480b0f7489a66c12559f64f6155c7031261d58e6dda91f438aa7a79969 Deleted: sha256:5b0b92f3990e2772d58c559c866d08436febf471792ad8502fce1f6ef568449e % docker image pull 192.168.56.101:30211/creationline/logstash:7.13.3 Error response from daemon: pull access denied for 192.168.56.101:30211/creationline/logstash, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
想定通り、MSRにログインしていない匿名ユーザではプルに失敗しました。
このように、MSRではレポジトリに対するアクセス制限を行う機能を備えているため、さまざまなユーザやチームが同一のプライベートレジストリを利用して共同作業する際に非常に強力な選択肢となりうるでしょう。
MSRのレポジトリを他のKubernetesから利用
では、実際にMSRのレポジトリを他のKubernetesクラスタから利用してみます。ここではホストマシン上にkindでKubernetesを準備し、そちらで実施します。kindのインストール等については省略します。
まず、次のYAMLマニフェストを準備し、kindのKubernetesクラスタがMSRを信頼するようにします。
kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 containerdConfigPatches: - |- [plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.56.101:30211".tls] insecure_skip_verify = true
このYAMLマニフェストを使ってインストールします。
% kind version kind v0.11.1 go1.16.4 linux/amd64 % kind create cluster --config kind.yaml Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.21.1) ✓ Preparing nodes ✓ Writing configuration ✓ Starting control-plane ✓ Installing CNI ✓ Installing StorageClass Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Not sure what to do next? Check out https://kind.sigs.k8s.io/docs/user/quick-start/ % kubectl cluster-info --context kind-kind Kubernetes control plane is running at https://127.0.0.1:40377 CoreDNS is running at https://127.0.0.1:40377/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. % kubectl get nodes NAME STATUS ROLES AGE VERSION kind-control-plane Ready control-plane,master 109s v1.21.1
ではこのKubernetes上に、MSRからイメージをプルしてPodを起動してみましょう。ログインが必要なコンテナイメージレジストリからプルするにはSecretを使います。詳細はCreate a Secret by providing credentials on the command lineを参照してください。
まず、MSRのWebUIにbobユーザでログインします。左のサイドバーの bob をクリックし、Profileを開き、上のAccess Tokensタブを開きます。
New access tokenボタンをクリックします。ここではDescriptionに「kind」と入力し、Createボタンをクリックします。
表示されたアクセストークンをどこか安全な場所に保存しておきます。二度と表示されないので注意しましょう。このアクセストークンはパスワードの代わりとして利用できます。ただしWebUIのログイン用には使えません。
このアクセストークンをKubernetesのSecretとして保存します。
% kubectl create secret docker-registry bob-msr --docker-server=https://192.168.56.101:30211/ --docker-username=bob --docker-password=cd22a466-4fd5-43d7-9e0a-d27d0380ca9c secret/bob-msr created
次のYAMLマニフェストでPodを作成します。
apiVersion: v1 kind: Pod metadata: name: bob-logstash spec: restartPolicy: Never containers: - image: 192.168.56.101:30211/creationline/logstash:7.13.3 name: logstash command: [ "echo", "hello-world" ] imagePullSecrets: - name: bob-msr
では、このPodをデプロイしてみましょう。
% kubectl apply -f bob-msr.yaml pod/bob-logstash created % kubectl get pod NAME READY STATUS RESTARTS AGE bob-logstash 0/1 Completed 0 13s % kubectl logs bob-logstash hello-world
想定通りに動作していることが確認できました。念のためdescribeの結果も見てみましょう。
% kubectl describe pod bob-logstash Name: bob-logstash Namespace: default Priority: 0 Node: kind-control-plane/172.20.0.2 Start Time: Wed, 05 Jan 2022 15:14:20 +0900 Labels: Annotations: Status: Succeeded IP: 10.244.0.6 IPs: IP: 10.244.0.6 Containers: logstash: Container ID: containerd://9f25e41641b7cc77a321e111eeee954047d7d75e72c4d3087420fa97aab09ce2 Image: 192.168.56.101:30211/creationline/logstash:7.13.3 Image ID: 192.168.56.101:30211/creationline/logstash@sha256:a24e6faa2337f4deaa903eb9036f01387414252d3f6649f0bfe471b897310c63 Port: Host Port: Command: echo hello-world State: Terminated Reason: Completed Exit Code: 0 Started: Wed, 05 Jan 2022 15:14:22 +0900 Finished: Wed, 05 Jan 2022 15:14:22 +0900 Ready: False Restart Count: 0 Environment: Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-sn5bz (ro) Conditions: Type Status Initialized True Ready False ContainersReady False PodScheduled True Volumes: kube-api-access-sn5bz: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: DownwardAPI: true QoS Class: BestEffort Node-Selectors: Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 109s default-scheduler Successfully assigned default/bob-logstash to kind-control-plane Normal Pulling 108s kubelet Pulling image "192.168.56.101:30211/creationline/logstash:7.13.3" Normal Pulled 65s kubelet Successfully pulled image "192.168.56.101:30211/creationline/logstash:7.13.3" in 42.99685449s Normal Pulled 6s kubelet Container image "192.168.56.101:30211/creationline/logstash:7.13.3" already present on machine Normal Created 4s kubelet Created container logstash Normal Started 4s kubelet Started container logstash
MSRからイメージをプルしてPodを起動していることがわかります。
MSRの脆弱性スキャンとその応用例
さて、先ほどMSRにプッシュした logstash:7.13.3 の脆弱性スキャンもそろそろ終わっているころでしょう。WebUIから確認してみましょう。
Vulnerabilitiesが更新されて、Criticalが14、Highが95もあることがわかります。View detailsをクリックして詳細を見てみます。
このように、2021年末に話題となったlog4shellの脆弱性もきちんと検出できています。MSRの脆弱性スキャンを利用することで危険なイメージを発見するだけでなく、使用を禁止することも可能です。
例えば、「Criticalな脆弱性の数が3未満であればプルを許可する」というポリシーを定義してみます。
この状態で logstash:7.13.3 をプルしてみましょう。
% docker image pull 192.168.56.101:30211/creationline/logstash:7.13.3 Error response from daemon: unknown: pull access denied against creationline/logstash: enforcement policies '381ef99c-d2c9-4a8e-a45f-42812d18c763' blocked request
このように、ポリシー違反のためプルに失敗しました。ポリシーの設定次第で、安全なイメージのみをコンテナあるいはPodとして利用できるようになります。
まとめ
本稿では、MKEから独立して利用できるようになったMirantis Secure Registry (MSR)バージョン3.0.0を、Vagrant/Virtualbox上にk0sでインストールした1ノードKubernetesにデプロイし、ユーザ・チーム・オーガニゼーションを作成してアクセス制御機能を簡単に確認し、MSRにプッシュしたイメージを別のKubernetesで利用してみました。またMSRの目玉機能の一つである脆弱性スキャンによるイメージの利用可能ポリシーの設定も簡単に見てみました。
「脆弱性スキャンやユーザ管理は行いたいが、Docker Hubではなく自社インフラ内にイメージレジストリを置きたい」「MSRの機能は魅力だが、既にKubernetesクラスタを持っているので、MKE必須では難しい」といったニーズを満たせる製品となったと思います。
ご覧いただいたように、k0s上にも簡単にデプロイできるので、気軽にお試しいただくことも可能です。
製品に関する質問や価格、ライセンス体系などにつきましてはこちらからお問い合わせください。