실습
- Harbor 설치 및 컨테이너 이미지 업로드(push)
- Kubernetes YAML 파일 내 사설 Repo 사용
- Harbor 이미지 보안 스캔 설정 사용
Why Harbor?
Kubernetes를 사용하기 위해서는 보안상의 이유로 로컬 컨테이너 이미지 Registry를 사용합니다. 특히 도커 허브가 유료화 되면서 도커 허브는 사용량 제한(공인 IP 6시간 당 200개 컨테이너 Pull)이 걸리는 경우가 자주 발생합니다.
이미지 레지스트리로 사용 가능한 몇가지 옵션이 있는데 그 중 가장 많이 사용하고 성숙도도 높은(CNCF Graduated) Harbor가 가장 적합합니다.
간단한 소개는 아래 공식 홈페이지 내용으로 대신 합니다.
What is Harbor?
Harbor is an open source container image registry that secures images with role-based access control, scans images for vulnerabilities, and signs images as trusted. A CNCF Incubating project, Harbor delivers compliance, performance, and interoperability to help you consistently and securely manage images across cloud native compute platforms like Kubernetes and Docker.
(Harbor는 역할 기반 접근 제어, 이미지 취약점 스캐닝, 이미지 서명 등의 기능을 갖춘 오픈소스 컨테이너 이미지 레지스트리입니다. CNCF Incubating(now graduated) 프로젝트인 Harbor는, Kubernetes와 Docker와 같은 클라우드 네이티브 플랫폼에서 이미지를 안전하고 일관적으로 관리할 수 있는 컴플라이언스와 성능, 상호 운영성을 제공합니다)
설치는 helm 통하여 쉽게 가능합니다.
[spkr@erdia22 45.Harbor (spkn02:redis)]$ helm pull harbor/harbor
[spkr@erdia22 45.Harbor (spkn02:redis)]$ tar xvfz harbor-1.6.1.tgz
[spkr@erdia22 45.Harbor (spkn02:redis)]$ mv harbor harbor-1.6.1
[spkr@erdia22 harbor-1.6.1 (spkn02:redis)]$ k create ns harbor
namespace/harbor created
[spkr@erdia22 harbor-1.6.1 (spkn02:redis)]$ kns harbor
Context "spkn02" modified.
Active namespace is "harbor".
values.yml 파일 수정
- service type, commonName(TLS 설정), storageClass 등을 아래와 같이 수정합니다.
: k3s 환경은 service type을 nodePort로 지정합니다. - VS Code를 사용하면 아래와 같이 편리하게 변경 내역 추적 가능합니다.
Helm harbor 설치
[spkr@erdia22 harbor-1.6.1 (spkn02:harbor)]$ helm install harbor -f my-values.yaml .
NAME: harbor
LAST DEPLOYED: Mon May 24 10:06:14 2021
NAMESPACE: harbor
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://harbor.spk.io
For more details, please visit https://github.com/goharbor/harbor
별 이슈가 없으면 아래와 같이 정상적으로 설치됩니다. 생각보다 많은 POD가 설치 됩니다. ^^ 1분 정도 지나면 아래와 같이 설치가 완료 됩니다.
[spkr@erdia22 harbor-1.6.1 (spkn02:harbor)]$ kgp (k get pod)
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
harbor-harbor-chartmuseum-9fdd94fd5-25fsc 1/1 Running 0 2m55s 10.233.96.77 node2 <none> <none>
harbor-harbor-core-84595656b6-lt4rp 1/1 Running 0 2m55s 10.233.90.81 node1 <none> <none>
harbor-harbor-database-0 1/1 Running 0 2m55s 10.233.96.76 node2 <none> <none>
harbor-harbor-jobservice-54f4df55b-pnggw 1/1 Running 0 2m55s 10.233.90.86 node1 <none> <none>
harbor-harbor-nginx-75c6dd67f5-472sn 1/1 Running 0 2m55s 10.233.96.70 node2 <none> <none>
harbor-harbor-notary-server-76f97648-fcndw 1/1 Running 1 2m55s 10.233.96.71 node2 <none> <none>
harbor-harbor-notary-signer-6b8fd9754c-22r5g 1/1 Running 1 2m55s 10.233.90.82 node1 <none> <none>
harbor-harbor-portal-6586fd8dbc-zjkt5 1/1 Running 0 2m55s 10.233.96.69 node2 <none> <none>
harbor-harbor-redis-0 1/1 Running 0 2m55s 10.233.96.73 node2 <none> <none>
harbor-harbor-registry-5cc696bcd5-gbq8z 2/2 Running 0 2m55s 10.233.90.88 node1 <none> <none>
harbor-harbor-trivy-0 1/1 Running 0 2m55s 10.233.90.87 node1 <none> <none>
개인 PC에서 접속을 위하여 생성된 Service LoalBalancer IP를 hosts 파일에 등록 합니다. IP는 service.loadbalancer로 확인 가능합니다.
[spkr@erdia22 harbor-1.6.1 (spkn02:harbor)]$ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
harbor LoadBalancer 10.233.16.123 172.17.28.160 80:32365/TCP,443:30265/TCP,4443:31885/TCP 4m19s
(이하 생략)
윈도우 hosts 파일 등록
hosts 파일 등록 후 접속 하시면 self signed 인증서를 사용하므로 아래와 같이 보안 경고가 발생합니다. 가볍게 무시하시고 접속합니다.
my-value.yml 파일에서 설정한 password(default Harbor12345)를 이용하면 정상적으로 접속 가능합니다.
컨테이너 이미지 push를 위하여 임의의 신규 project를 생성 합니다.
컨테이너 이미지 업로드(Push)
도커 이미지 tag 변경 후 push 해 보겠습다. tag는 사설 도메인 이름과 위에서 생성한 Project 이름을 사용합니다.
[spkr@erdia22 ~ (spkn02:harbor)]$ docker tag busybox harbor.spk.io/spk/busybox
[spkr@erdia22 ~ (spkn02:harbor)]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
harbor.spk.io/spk/busybox latest c55b0f125dc6 2 weeks ago 1.24MB
처음 업로드 하려면 CLI 환경에서 Login이 필요합니다.
[spkr@erdia22 harbor-1.6.1 (spkn02:harbor)]$ docker login harbor.spk.io
Authenticating with existing credentials...
Stored credentials invalid or expired
Username (admin): admin
Password:
Login Succeeded
self-signed 인증서를 사용하였으므로 개인 PC docker 설정에 아래의 insecure-registries - harbor.spk.io URL 등록합니다.
관련 설정이 완료 되었습니다. 이제 정상적으로 이미지 push 가능합니다.
[spkr@erdia22 harbor-1.6.1 (spkn02:harbor)]$ docker push harbor.spk.io/spk/busybox
Using default tag: latest
The push refers to repository [harbor.spk.io/spk/busybox]
36b45d63da70: Pushed
latest: digest: sha256:f1e9b10f3e11f03cc1881415598044364124c838dbc616621403bb88099ba8af size: 527
Admin UI에서 정상적으로 업로드 된 이미지 확인하실 수 있습니다.
Kube YAML 적용
다음으로 Kube YAML 파일에 등록 하겠습니다.
Deployment 예제
apiVersion: apps/v1
kind: Deployment
metadata:
name: busybox
namespace: default
labels:
app: busybox
spec:
replicas: 1
selector:
matchLabels:
app: busybox # POD label과 일치
template:
metadata:
labels:
app: busybox # Selector label과 일치
spec:
containers:
- name: busybox
image: harbor.spk.io/busybox
command:
- "/bin/sh"
- "-c"
- "sleep inf"
YAML 배포해 보겠습니다.
[spkr@erdia22 06.Deployment (spkn02:harbor)]$ ka(k apply -f) busybox-deploy.yml
deployment.apps/busybox created
[spkr@erdia22 06.Deployment (spkn02:default)]$ kgpw (k get pod -w)
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox-7fb4c8559-kxs4z 0/1 ContainerCreating 0 1s <none> node2 <none> <none>
busybox-7fb4c8559-kxs4z 0/1 ErrImagePull 0 4s 10.233.96.79 node2 <none> <none>
처음은 아래와 같이 에러가 발생 합니다.
[spkr@erdia22 06.Deployment (spkn02:default)]$ k describe pod busybox-7fb4c8559-kxs4z
Name: busybox-7fb4c8559-kxs4z
(생략)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 9s default-scheduler Successfully assigned default/busybox-7fb4c8559-kxs4z to node2
Normal Pulling 8s kubelet Pulling image "harbor.spk.io/spk/busybox"
Warning Failed 5s kubelet Failed to pull image "harbor.spk.io/spk/busybox": rpc error: code = Unknown desc = failed to pull and unpack image "harbor.spk.io/spk/busybox:latest": failed to resolve reference "harbor.spk.io/spk/busybox:latest": failed to do request: Head https://harbor.spk.io/v2/spk/busybox/manifests/latest: dial tcp 172.17.29.154:443: connect: no route to host
Warning Failed 5s kubelet Error: ErrImagePull
Normal BackOff 5s kubelet Back-off pulling image "harbor.spk.io/spk/busybox"
Warning Failed 5s kubelet Error: ImagePullBackOff
사설 IP를 사용하므로 harbor.spk.io 에 대한 도메인 IP 정보가 없어서 발생합니다. 해당 URL 정보를 각 노드의 /etc/hosts 등록 해야 합니다. (각 node의 docker 데몬에서(또는 crio) 에서 이미지를 다운 합니다.)
만약, ansible 사용하시면 아래 playbook으로 /etc/hosts 등록이 가능합니다.
- hosts: ctrs
become: yes
tasks:
- name: Add /etc/hosts
lineinfile:
path: /etc/hosts
line: "172.17.28.160 harbor.spk.io" # line 추가
[spkr@erdia22 02.module (spkn02:default)]$ ansible-playbook lineinfile-add.yml
PLAY [ctrs] *********************************************************************************************************************************************************************************************************
TASK [Add /etc/hosts] ***********************************************************************************************************************************************************************************************changed: [ctr2]
changed: [ctr1]
changed: [ctr3]
PLAY RECAP **********************************************************************************************************************************************************************************************************ctr1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ctr2 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ctr3 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
결과를 확인해 보겠습니다.
[spkr@erdia22 02.module (spkn02:default)]$ ansible ctrs -a "cat /etc/hosts"
ctr1 | CHANGED | rc=0 >>
(생략)
# Ansible inventory hosts END
172.17.28.160 harbor.spk.io
정상적으로 등록 되었습니다.
추가로 다음과 같이 에러 메시지가 발생하면 insecure registry 관련 설정을 crio 설정 파일(crio.conf)에 등록합니다.
[spkr@erdia22 06.Deployment (kspray:default)]$ k describe pod busybox-7fb4c8559-mkrsx
Name: busybox-7fb4c8559-mkrsx
(생략)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 5s default-scheduler Successfully assigned default/busybox-7fb4c8559-mkrsx to ksp2
Normal Pulling 4s kubelet Pulling image "harbor.spk.io/spk/busybox"
Warning Failed 4s kubelet Failed to pull image "harbor.spk.io/spk/busybox": rpc error: code = Unknown desc = error pinging docker registry harbor.spk.io: Get "https://harbor.spk.io/v2/": x509: certificate signed by unknown authority
Warning Failed 4s kubelet Error: ErrImagePull
Normal BackOff 2s (x2 over 3s) kubelet Back-off pulling image "harbor.spk.io/spk/busybox"
Warning Failed 2s (x2 over 3s) kubelet Error: ImagePullBackOff
crio 설정 파일(crio.conf)에 아래와 같이 insecure_registries에 해당 도메인을 등록 합니다.
[spkr@ksp3 ~]$ sudo vi /etc/crio/crio.conf
(생략)
# List of registries to skip TLS verification for pulling images. Please
# consider configuring the registries via /etc/containers/registries.conf before
# changing them here.
insecure_registries = [
"harbor.spk.io"
]
(생략)
registries = [
"docker.io",
"harbor.spk.io"
]
이제 다시 YAML 배포 하시면 아래와 같이 정상적으로 이미지를 가져오시는 걸 확인 하실 수 있습니다.
[spkr@erdia22 redis-14.1.0 (spkn02:default)]$ kgp
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox-6c4cc6fc48-8klsp 1/1 Running 0 4h44m 10.233.96.84 node2 <none> <none>
Harbor 이미지 보안 Scan
다음으로 Harbor 주요 기능인 이미지 보안 Scan 기능을 이용해 보겠습니다.
Scan 설정
- Project - Configuration -Vulnerability scanning - Automatically scan images on push 체크하면 이미지가 업로드되면 자동으로 Scan 기능을 실행 합니다.
혹은 기존에 업로드된 이미지는 레포 선택 후 아래 SCAN 버튼을 클릭 하시면 됩니다.
- 수동 scan
NGINX 이미지를 Push 하고 보안 취약점을 확인해 보겠습니다.
nginx 이미지 레포를 확인하면 아래와 같이 Vulnerabilities 확인 가능합니다. nginx:latest 사용했는데 보안 취약점이 엄청 납니다. (164 취약점.. critical 9개...)
문제는 nginx 보안 취약점이 있어도 수정 하기가 쉽지 않다는 것 입니다. 전체 이미지 취약점 리스트만 50만개라 하고 그리고 실시간으로 업데이트 되어 일일이 대응하는 것은 사실상 불가능에 가깝습니다.
현재로써는 보안 취약점 확인 정도에 그쳐야 할 것 같습니다.
이상 Harbor 사용법에 알아 보았습니다. HA Test, Data 삭제 테스트 등이 필요하나 이미지 보관이 목적이라 특별히 서비스 고가용성 요구 사항이 높지 않아 디폴트로 사용하셔도 충분 할 것 같습니다.
참조
https://engineering.linecorp.com/ko/blog/harbor-for-private-docker-registry/
'쿠버네티스 교육' 카테고리의 다른 글
21. Kube 교육 - ArgoCD for GitOps (0) | 2021.06.04 |
---|---|
20. Kube 교육 - Local GitLab Repository (0) | 2021.06.04 |
18. Kube 교육 - Loki Logging System (0) | 2021.06.04 |
17. Kube 교육 - AlertManager 설정 (2) | 2021.06.04 |
16. Kube 교육 - Grafana Custom 대시보드 생성 (0) | 2021.06.04 |