쿠버네티스 교육

19. Kube 교육 - Harbor

Jerry_이정훈 2021. 6. 4. 16:49
728x90

실습

  • 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/

 

Private Docker Registry를 구축하기 위한 오픈소스 Harbor 도입기 - LINE ENGINEERING

안녕하세요. LINE+에서 엔지니어로 일하고 있는 이지현입니다. 저는 현재 전 세계에 퍼져 있는 수많은 LINE 엔지니어들이 좀 더 효율적으로 업무를 수행할 수 있도록 여러 가지 공통 엔지니어링

engineering.linecorp.com

 

반응형