3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Kubernetesにおけるコンテナイメージスキャン

Last updated at Posted at 2021-12-22

1.はじめに
2.検証環境の構成
3.前作業
4.minikubeのインストール
5.Gitlabのインストール
6.Helmのインストール
7.KubernetesとGitlabを連携
8.CICDのパイプラインにTrivyによるコンテナイメージスキャンを追加

#1. はじめに
この記事は、NTTコムウェア Advent Calendar 2021 23日目の記事です。
NTT コムウェアでセキュリティエンジニアの仕事をしている山原です。
この記事では、社内のProxy環境下でMinikubeを使用してKubernetes環境を構築し、
GitLabのCI/CDのパイプラインの中にコンテナのイメージスキャンを組み込んだ検証結果をまとめました。
KubernetesやCI/CDには興味があるけど、社内環境で構築するのがしんどいと思う人が参考にできる内容となっています。

また、コンテナイメージの脆弱性スキャンが必要な理由としては、DockerHubに公開されている400万イメージのうち51パーセントに重大な脆弱性を抱えています。
https://www.infoq.com/jp/news/2021/03/dockerhub-image-vulnerabilities/

DockerコンテナやKubernetesは、現在のエンジニアリングには欠かせない便利なツールとなっていますが、システムにコンテナの脆弱性を盛り込めば、外部からの攻撃対象となってしまいます。安全にコンテナイメージを使用するために、脆弱性スキャンを取り入れることを検討してください。
皆様良きコンテナライフを!!

##やりたいこと
オンプレ環境にGitlabを構築し、minikubeで作成したkubernetes環境と連携をします。
CICDのパイプラインの上でプライベートコンテナレジストリにおける脆弱性スキャンを実施し、
コンテナイメージの安全性を確かめます。

image.png

#2. 検証環境の構成
OS:CentOS Stream release 8
GitLab CE 14.5.2
minikube version: v1.24.0
Docker Version 19.03.9

#3. 前作業

  • サーバ証明書の設定
  • Proxyの設定
  • kubectlをインストール
  • Dockerのインストール
  • Dockerのレジストリの証明書を設定

サーバ証明書の設定

社内で配布しているルート証明書を以下のディレクトリに配置する

cp ca.crt /etc/pki/ca-trust/source/anchors/
update-ca-trust extract

Proxyの設定

/etc/profileにproxyの設定を追記する
no_proxyの設定まで実施すること

vi /etc/profile

PROXY='XXXXXXXXX:8080' # proxyサーバのドメインとポートを指定
export http_proxy=$PROXY
export HTTP_PROXY=$PROXY
export https_proxy=$PROXY
export HTTPS_PROXY=$PROXY
export no_proxy=127.0.0.1,localhost,192.168.1.1/16

kubectlのインストール

1.yumにkubernetesのrepoを追加する

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

2.kubectlをインストールする

yum install -y kubectl

インストール済み:
  kubectl-1.22.4-0.x86_64

Dockerのインストール

1.インストール用のtarファイルをダウンロードする

wget --no-check-certificate  https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz 

2.tarファイルを展開する

tar xzvf docker-19.03.9.tgz

3.コマンドを使用可能な状態にする

chown root:root docker/*
cp docker/* /usr/bin/

4.dockerサービスの設定をする

[root@hogehoge]#  cat << EOF > /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
BindsTo=containerd.service
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
EOF

5.Dockerソケットを設定する

#cat << EOF > /usr/lib/systemd/system/docker.socket
[Unit]
Description=Docker Socket for the API
PartOf=docker.service

[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target
EOF

# cat << EOF >/usr/lib/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd
KillMode=process
Delegate=yes
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity

[Install]
WantedBy=multi-user.target
EOF

##Dockerレジストリの証明書を設定

Proxy配下では使用するDockerレジストリに証明書を設定しないとコンテナイメージをpullすることができない。

1.証明書を格納するためのディレクトリを作成する

cd /etc/docker/certs.d
mkdir registry-1.docker.io
mkdir k8s.gcr.io
mkdir ghcr.io

2.ルート証明書を配置する

cp /tmp/ca.crt /etc/docker/certs.d/registry-1.docker.io
cp /tmp/ca.crt /etc/docker/certs.d/k8s.gcr.io
cp /tmp/ca.crt /etc/docker/certs.d/ghcr.io

3.Dockerに証明書を反映させる

sudo systemctl daemon-reload
sudo systemctl restart docker

#4. minikubeのインストール

1.swapをoffにする

swapoff -a

2.minikubeのインストール資材をダウンロードし、コマンドに実行権限を与える

wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
cp minikube-linux-amd64 /usr/local/bin/minikube
chmod 755 /usr/local/bin/minikube

3.minikubeのバージョンを確認する

minikube version
minikube version: v1.24.0
commit: 76b94fb3c4e8ac5062daf70d60cf03ddcc0a741b

4.minikubeをスタートする
今回はkvm2を指定する。Dockerを指定しても大丈夫
minikubeはroot実行できない

minikube start --vm-driver=kvm2  --cache-images=false --docker-env HTTP_PROXY=$HTTP_PROXY --docker-env HTTPS_PROXY=$HTTPS_PROXY --listen-address=0.0.0.0

5.minikubeにも証明書をインストールする
一旦minikubeのシングルクラスタを削除して、所定のディレクトリにPEMファイルを配置する

minikube delete    
openssl x509 -in ca.crt -out tmp.der -outform DER
openssl x509 -in tmp.der -inform DER -out ca.pem -outform pem
cp ca.pem /home/${USER}/.minikube/certs/
minikube start --vm-driver=kvm2  --cache-images=false --docker-env HTTP_PROXY=$HTTP_PROXY --docker-env HTTPS_PROXY=$HTTPS_PROXY --listen-address=0.0.0.0

6.kubectlコマンドを使用できるようにminikubeのユーザコンテキストに切り替える

kubectl config use-context minikube

#5. Gitlabをインストールする
minikube上でGitlabのpodを作成すると、メモリの制約の問題でおすすめできない
今回はサーバOS上にGitlabをインストールする

1.インストール資材をダウンロードして実行する

dnf install gitlab-ce

2./etc/gitlab/gitlab.rbを編集し、外部からGitlabとコンテナレジストリを公開する

vi /etc/gitlab/gitlab.rb
external_url 'http://XXXXXXXXXXXXX:1010' ← コメントを外して外部からアクセスできるURLを設定する。IPアドレスでも良い
registry_external_url 'http://XXXXXXXXXXXXX:2020' ← コメントを外して外部からアクセスできるURLを設定する。IPアドレスでも良い

3.gitlabのコンフィグを読み直す

/opt/gitlab/embedded/bin/runsvdir-start &
gitlab-ctl reconfigure

4.Gitlabの初期パスワードを確認する
rootでログインするパスワードとなる

cat /etc/gitlab/initial_root_password

5.ブラウザで外部に公開したURLにアクセスし、適当なグループプロジェクトを作成する

#6. helmをインストールする
1.インストール資材をダウンロードする

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3

2.資材を使ってインストールする

chmod 700 get_helm.sh
./get_helm.sh

#7. KubernetesとGitlabを連携

1.kubernetes上にgitlab-runner用のサービスアカウントを作成する

kubectl apply -f gitlab-admin-service-account.yaml

(gitlab-admin-service-account.yaml)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: gitlab-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: gitlab
    namespace: kube-system

2.Kubernetesと連携する
Gitlabにアクセスして、AdminエリアよりKubernetesを選択し、「Connect existing cluster」をクリックし、必要な情報を入力する

image.png

Kubernetes cluster name: minikube
API URL: /home/XXXXX/.kube/config のserverを参照する
CA Certificate : /home/XXXXX/.kube/config のclient-certificateを参照する
残りはデフォルトの設定

3.[Add Cluster]をクリックする
image.png

4.gitlabrunnerのRegistrationTokenを確認する
作成したグループのSettingsよりCI/CDを選択し、Runnersの詳細を見ると[RegistrationToken]が表示されているので、コピーする。
image.png

5.Helmを使用してgitlab runnnerをデプロイする
runnerRegistrationTokenに先ほどコピーしたTokenを入力する

helm install --namespace gitlab gitlab-runner gitlab/gitlab-runner --set gitlabUrl=http://XXXXXXXXXXX:1010/  --set runnerRegistrationToken=XXXXXXXXXXXXX--set privileged=true --set rbac.create=true --set runners.config="
[[runners]]
  clone_url = \"http://xxxxxxxxxx:1010/\"
  [runners.kubernetes]
    image = \"ubuntu:16.04\"
 "

6.gitlab runnerが正常に立ち上がっているかを確認する
正常にRunning状態になっていることを確認しておく

$ kubectl get po -n gitlab
NAME                                           READY   STATUS    RESTARTS   AGE
gitlab-runner-gitlab-runner-8546485df9-f58c6   1/1     Running   0          6d20h

#8. CICDのパイプラインにTrivyによるコンテナイメージスキャンを追加

1.Gitlabのパイプラインの中でビルドをする時にDocker in Docker(Dind)を使用するため、
 コンテナが外部と疎通ができるように、Proxyと証明書の設定をしておく必要がある。
[settings]-[CI/CD]-[Variables]に証明書を変数として登録しておく。(管理は厳重に!)

image.png

2.Gitlabに作成したプロジェクトの上にDockerファイルと**.gitlab-ci.yml**を作成すれば、
 コンテナのイメージスキャンは実施できる。
 今回は、どなたでもパイプライン上でイメージスキャンを実行できるように[環境準備]、[テスト]、[デプロイ]をスキップする。
 

(.gitlab-ci.yml)
stages:
  - prepare
  - test
  - build
  - scan
  - deploy

prepare-job:
  stage: prepare
  script:
    - echo "Suceess"

test-job:
  stage: test
  script:
    - echo "Suceess test"

build-job:
  stage: build
  image: docker:dind
  variables:
    DOCKER_DRIVER: overlay2
    http_proxy: http://XXXXXXXXXXXX:8080
    https_proxy: http://XXXXXXXXXXXXX:8080
    NO_PROXY: 127.0.0.1,localhost,192.168.1.1/16
    DOCKER_HOST: /var/run/docker.sock
  services:
    - docker:dind
  script:
    - touch /usr/local/share/ca-certificates/root.crt
    - echo "${rootca}" >> /usr/local/share/ca-certificates/root.crt
    - update-ca-certificates
    - docker build ./-t (GitlabregistryのURI)/trivy-test2:1.0
    - dockerd --insecure-registry=XXXXXXXXXXX &
    - sleep 5
    - docker login XXXXXXXX:2020 -u (Gitlabのユーザ) -p (Gitlabのパスワード)
    - docker build ./-t GitlabregistryのURI)/trivy-test1.0
    - docker push GitlabregistryのURI)t/trivy-test1.0

scan-job:
  stage: scan
  image: docker.io/aquasec/trivy
  variables:
    http_proxy: http://XXXXXXXXXXXX:8080
    https_proxy: http://XXXXXXXXXXXXX:8080
    NO_PROXY: "127.0.0.1,localhost,192.168.1.1/16"
    TRIVY_USERNAME: "Gitlabユーザ"
    TRIVY_PASSWORD: "Gitlabパスワード"
    TRIVY_NON_SSL: "true"
  script:
    - touch /usr/local/share/ca-certificates/root.crt
    - echo "${rootca}" >> /usr/local/share/ca-certificates/root.crt
    - update-ca-certificates
    - trivy GitlabregistryのURI)/trivy-test1.0
  artifacts:
    when: always
    reports:
      scan-job: gl-container-scanning-report.json


test-deploy:
  stage: deploy
  script:
    - echo "Suceess deploy"

(Dockerfile)

FROM node:8.11-alpine

WORKDIR /usr/src/app
ENV http_proxy="XXXXXXXX:8080"
ENV https_proxy="XXXXXXXXXXX:8080"

ARG NODE_ENV
ENV NODE_ENV $NODE_ENV

COPY package*.json /usr/src/app/
RUN npm install

COPY . /usr/src/app

ENV PORT 5000
EXPOSE $PORT
CMD [ "npm", "start" ]

3.Dockerファイルと**.gitlab-ci.yml**をGitlabの任意のプロジェクトにpushすれば、CICD+コンテナイメージスキャンのジョブが自動起動する
パイプラインの実行中の画面

image.png

4.パイプラインの実行が成功するとすべてグリーンのチェック状態となる。

image.png

5.イメージスキャンジョブの中身を見ると、脆弱性スキャンが実行されていることがわかる。
 gl-container-scanning-report.jsonとしてジョブの結果はレポートとして保存される。

image.png

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?