이쿠의 슬기로운 개발생활

함께 성장하기 위한 보안 개발자 EverNote 내용 공유

Kubernetes/Kubernetes 보안

Kubernetes image인증 - Portieris

이쿠우우 2020. 12. 22. 21:00
반응형

 

 

Kubernetes image인증 - Portieris

(Kubernetes DCT 연동)

 

 


[Container image 인증 관련 글 목록]

Notary Service 란?

Docker Notary : Docker Content Trust (DCT)

DCT를 사용해서 Dcoker Hub에 서명된 Trust Image Push 하기

Notary와 DCT를 사용해서 Private Registry에 서명된 Trust Image Push하기

개인 인증서를 사용해서 Notary Service 구동

kubernetes image인증 - Portieris

kubernetes image인증 - Portieris2


 

목표

개인 Notary Server를 만든 후

Docker에서 DCT설정을 사용해서 

image 인증하는 방법을 알았음.

그렇다면 해당 설정과 동일하게 kubernetes 에서도

인증된 image만 pod로 생성될 수 있도록

Pod image 인증 방법을 알아봄.

 


kubernetes에서 DCT 연동 방법 찾기

kubernetes도 결국 container를 생성하는것은 

container runtime tool인 Docker임으로 

모든 Worker Node에 Docker DCT를 설정하면

image 인증이 간단하게 해결될 것이라고 생각하고 test해봄.

 

Test 결과

 

다양한 방법으로 모든 Node에 Docker DCT를 설정해서

Kubernetes에 적용을 시도함.

Worker Node의 Docker로 Container를 생성하는 과정으로는

image pull push test 결과 DCT 정상 동작 되는것은 확인했으나

kubernetes의 kubectl 명령을 통해서 image pull 할 시

Worker Node에 DCT설정이 되어있지만

결국 kubernetes에서는 DCT 적용가 적용되지 않음

 

 

DCT가 kubernetes에 적용되지 않는 이유

Kubernetes의 각종 Pod를 포함한 각종 oject 생성요청은

kube-apiserver 모듈을 받아서 해당 요청을 처리함.

즉 DCT는 kube-apiserver에 설정이 되야 적용됨.

kubernetes 에서 DCT를 사용하기 위해서는 

kube-apiserver에 적용할 수 있는 Addon이 필요함.

 

결과

공식적으로 kubernetes 에서 DCT는 지원되지 않음

[결과 참고 Site]

https://github.com/kubernetes/kubernetes/issues/30603

https://medium.com/sse-blog/container-image-signatures-in-kubernetes-19264ac5d8ce

 

해결법

하지만 특정 Addon을 통해 kubernetes에서 DCT 연동이 가능함.

 


 

후보 1 : Connaisseur 

Kubernetes notary 적용 방법으로 

독일의 개발자가 오픈소스로 공개한 Addon.

하지만 정보가 거의 없음.

 

[적용 시도]

기존 kubernetes server에 Connaisseur 적용 중

정상 운영 중인 kubernetes 각종 pod와 service, namespace, 설정파일 정보 등이 모두

Connaisseur 로 강제로 설정되어 

기존 kubernetes server가 Error 가 발생함.

 

[결과]

일단 자료가 너무 없고 Addon의 완성도도 떨어진다고 판단함.

적용 시도 중 많은 버그로 인한 원인불명 오류로 수집번 cluster를 재설치함.

적용에 치명적인 이슈가 많음. 

이러한 이유로 Connaisseur은 

kubernetes notary 구성에 사용하기에 적절하지 못하다고 판단함.

 

[Connaisseur 제거 후 deployment 안되던 오류 해결법]

kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io 

kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io 

조회해서 나오는 webhook 삭제

 

 

 

후보 2 : Portieris

IBM에서 개발한 Kubernetes notary 적용 Addon.

2018년도에 개발된 Addon으로

아직 많은 자료는 없지만 IBM이기에 믿고 사용해보기로 함.

Portieris 는 Mutating Addmission Controller Webhook 기반으로 동작하여

kube-apiserver를 통해 오는 요청을 Portieris webhook으로 보내서 

request를 변경한 후 respone을 주는 형시긍로

Portieris Webhook이 DCT역할을 수행해주어

Kubernetes 에서 images 인증을 수행할 수 있게 해주는 Addon임.

해당 Addon을 사용해서 Kubernetes image 인증을 시도해보겠음.

 

[참고 Site]

https://github.com/IBM/portieris

https://cloud.ibm.com/docs/Registry?topic=Registry-security_enforce#assign_user_policy

https://www.youtube.com/watch?v=JK70k_B87mw&t=1s

 


 

Portieris Addon 설치과정

설치과정 중에 마주한 이슈를 경험한 순서 그대로 기록함.

Test 환경

Node 정보

Master Node server

 OS = CentOS 7

 리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64

 docker version : 1.13.1

 api verison : 1.26

 

Worker Node server 1

 OS = CentOS 7

 리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64

 docker version : 1.13.1

 api verison : 1.26

 

Worker Node server 2

 OS = CentOS 7

 리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64

 docker version : 1.13.1

 api verison : 1.26

 

Kubernetes version

1.18

 

 

 

Test에 사용한 Private Registry 정보

[ Private Registry 주소 ]

iksoon.docker.com:5000

IP : 10.0.2.5

 

[ K8s에서 Private Registry 접속 설정완료. ]

/etc/pki/ca-trust/source/anchors 경로에 crt인증서가 있음.

root-ca.crt = Notary Server 인증서

server.crtiksoon.docker.com https 접근 용 인증서

 

[ Private Registry Image 정보 ]

domain_iksoon_tomcat:1.0.0 = 인증 안됨.

domain_iksoon_tomcat:1.0.1 = 인증 됨.


 

1. Portieris Download

git clone https://github.com/IBM/portieris.git

 

 

2. Helm 파일 편집

2020.09.14일 기준 Portieris 0.8.0 version 기준으로

기존의 helm설정을 그대로 사용하면 다양한 error가 발생함

그래서 설정 파일을 변경해줘야 정상적으로 설치됨.

 

[설정 변경]

vi ~/portieris/helm/portieris/values.yaml

에서 image/tag 를 확인

tag 가 기존에는 0.8.0next 가 되어있는데

이를 0.8.0 으로 변경

 

3. ibm-system namespace 생성

Portieris Helm에서 Job 동작 시 ibm-system namespace가 필요한데

helm 에 해당 namespace생성 과정이 포함되어있지 않아서

오류가 발생함.

해당 오류 해결을 위해 직접 namespace생성함.

 

[명령어]

kubectl create ns ibm-system

 

 

4. Portieris에 사용되는 인증키를 생성

K8s와 Portieris webhook server 간 통신에 필요한 인증키를 생성하는 작업.

 

[명령어]

./helm/portieris/gencerts

 

 

5. Portieris 설치

[명령어]

helm install portieris --create-namespace --namespace portieris helm/portieris

 

설치 완료.

 

 

 


 

Portieris Notary 연동 Test

 

Portieris 정책 생성

정책으로는 ImagePolicy와 ClusterImagePolicy 가 있음.

 

ImagePolicy = 특정 namespace에만 적용되는 정책

ClusterImagePolicy = kubernetes cluster 전체에 적용되는 정책

 

[예제 ImagePolicy.yaml]

apiVersion: securityenforcement.admission.cloud.ibm.com/v1beta1
kind: ImagePolicy
metadata:
  name: iksoon-custom
  namespace: iksoon-ns
spec:
   repositories:
    - name: "iksoon.docker.com:5000/*"
      policy:
        trust:
          enabled: true
          trustServer: "https://notary-server:4443"

 

 

정책 생성 후 Pod 생성

image는 

iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.0

을 지정함.

 

[정책에서 정해지지 않은 Registry에서 image pull 시도할 경우 ]

 

예) docker hub의 peksoon Registry 에서 image pull 시도.

 

Error from server: error when creating "2_deployment.yaml": admission webhook "trust.hooks.securityenforcement.admission.cloud.ibm.com" denied the request:

Deny "peksoon/iksoon_tomcat:1.0.6", no matching repositories in the ImagePolicies

 

 

첫번째 ERROR 발생.

설정된 Registry에서 image pull 시도 했는데 trustServer(notary-server)를 바라보지 못하는 오류 발생 

 

오류명

Error from server: error when creating "1_deployment.yaml": admission webhook "trust.hooks.securityenforcement.admission.cloud.ibm.com" denied the request:

trust: policy denied the request: Deny "iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.0", failed to get content trust information: dial tcp: lookup notary-server on 10.96.0.10:53: no such host

 

원인

Kubernetes의 CoreDNS가 Host Name을 확인할 수 없기 때문. (상위 예제 환경에서의 hostname = notary-server)

Notary Server가 TLS 인증서에서 해당 Host Name을 사용하므로 Host Name을 IP 주소로 바꿀 수 없음. 

따라서 Kuberntes에서 이 Host Name을 확인하도록해야함.

이어서 이 오류의 해결 방법을 찾아봄.

 


 

 

첫번째 ERROR 해결법

Kubernetes 에서는 자체 DNS Server 로 CoreDNS를 사용 중.

notary-server no such host 오류가 발생하는 이유는 CoreDNS에서 

해당 Domain을 찾기 못하기 때문.

이러한 문제를 해결하기 위해

notary-server 정보를 가지고 있는 DNS를 추가해야함.

CoreDNS에서 host를 찾기 못하면 

다른 DNS에서 찾을 수 있도록

unbound DNS 를 구축하고

CoerDNS에서 StubDomain설정으로 unbound DNS를 설정하는 작업을 진행함.

 

[참고]

K8s version 1.12 이전는 kube-dns 를 사용했었으나

이후 version부터는 CoreDNS를 사용함.

 

Unbound DNS 설치

 

1. Unbound DNS를 다운받기 위해 helm repository 추가

helm repo add stable https://kubernetes-charts.storage.googleapis.com/

 

 

 

2. Helm으로 Unbound DNS 실행

helm install  unbound --create-namespace --namespace=unbound --set-string localRecords[0].name=notary-server,localRecords[0].ip=10.0.2.5,allowedIpRanges[0]=10.0.2.0/25,allowedIpRanges[0]=10.244.0.0/16 stable/unbound  

 

 

CoreDNS에 StubDomain으로 Unbound DNS 설정

1. Unbound DNS 의 Service Object Cluster IP 확인

[명령어]

kubectl -n unbound get svc | grep ClusterIP | awk '{print $3}'

 

[결과]

service : 10.98.217.155

 

 

2. CoreDNS 설정 변경

 

[명령어]

kubectl edit cm coredns -n kube-system

 

[설정 추가]

apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        health {
           lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
           ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf 
        cache 30
        loop
        reload
        loadbalance
    }
    notary-server:53 {
        errors
        cache 30
        forward . 10.98.217.155 # Unbound DNS의 Service object cluster ip.
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2020-08-27T00:14:37Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data: {}
    manager: kubeadm
    operation: Update
    time: "2020-08-27T00:14:37Z"
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        f:Corefile: {}
    manager: kubectl
    operation: Update
    time: "2020-09-09T00:02:49Z"
  name: coredns
  namespace: kube-system
  resourceVersion: "2574871"
  selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
  uid: 0f3f31b3-2799-47ab-977d-d43baa8620ab

 

[ 옵션 설명 ]

errors:

오류가 표준 출력(stdout)에 기록된다.

 

health:

CoreDNS의 상태(healthy)가 http://localhost:8080/health 에 기록된다. 

이 확장 구문에서 lameduck 은 프로세스를 비정상 상태(unhealthy)로 만들고,

프로세스가 종료되기 전에 5초 동안 기다린다.

 

ready:

8181 포트의 HTTP 엔드포인트가, 모든 플러그인이 준비되었다는 신호를 보내면 200 OK 를 반환한다.

 

kubernetes:

CoreDNS가 쿠버네티스의 서비스 및 파드의 IP를 기반으로 DNS 쿼리에 대해 응답한다. 

해당 플러그인에 대한 세부 사항은 CoreDNS 웹사이트에서 확인할 수 있다. 

ttl 을 사용하면 응답에 대한 사용자 정의 TTL 을 지정할 수 있으며, 기본값은 5초이다.

허용되는 최소 TTL은 0초이며, 최대값은 3600초이다. 레코드가 캐싱되지 않도록 할 경우, 

TTL을 0으로 설정한다. pods insecure 옵션은 kube-dns 와의 하위 호환성을 위해 제공된다. 

pods verified 옵션을 사용하여, 일치하는 IP의 동일 네임스페이스(Namespace)에 파드가 존재하는 경우에만

A 레코드를 반환하게 할 수 있다. pods disabled 옵션은 파드 레코드를 사용하지 않을 경우 사용된다.

 

prometheus:

CoreDNS의 메트릭은 프로메테우스 형식(OpenMetrics 라고도 알려진)의

http://localhost:9153/metrics 에서 사용 가능하다.

 

forward:

쿠버네티스 클러스터 도메인에 없는 쿼리들은 모두 사전에 정의된 리졸버(/etc/resolv.conf)로 전달된다.

 

cache:

프론트 엔드 캐시를 활성화한다.

 

loop:

간단한 전달 루프(loop)를 감지하고, 루프가 발견되면 CoreDNS 프로세스를 중단(halt)한다.

 

reload:

변경된 Corefile을 자동으로 다시 로드하도록 한다.

컨피그맵 설정을 변경한 후에 변경 사항이 적용되기 위하여 약 2분정도 소요된다.

 

loadbalance:

응답에 대하여 A, AAAA, MX 레코드의 순서를 무작위로 선정하는 라운드-로빈 DNS 로드밸런서이다.

 

 

3. CoreDNS 설정 적용

[명령어]

kubectl delete pod --namespace kube-system --selector k8s-app=kube-dns

 

CoreDNS는 reload 설정이 되어있어서 

Corefile이 변경되면 약 2분 후 자동으로 다시 로드하지만 2분도 꽤 긴시간으로 느껴지니 바로 적용하기 위해

상위 명령으로 pod를 삭제하고 상위에서 설정한 정보로 자동으로 재생성되도록 함.

 

 

결과 

 

상위 설정 후 Pod 생성 결과 : 다른 에러 발생

상위 설정을 완료하니 

이제 정상적으로 Host는 바라봄. 

하지만 또 다른 오류가 나타남.

 

오류명

Error from server: error when creating "1_deployment.yaml": admission webhook "trust.hooks.securityenforcement.admission.cloud.ibm.com" denied the request:

trust: policy denied the request: Deny "iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.0", failed to get content trust information: x509: certificate signed by unknown authority

 

원인

Private Registry의 Domain 주소를 확인해서 접근을 시도했지만 여전히 iksoon.docker.com:5000에 접근할 수가 없음.

Private Registry가 인증서를 검증 할 수 없기 때문에 오류가 발생한 상황.

 


 

 

두번째 ERROR 해결법

 

해결책

Private Regitsry에 접근하기 위해 인증서를 Portieris에 설정해줘야 함.

 

 

configMap 으로 인증서를 Pod에 직접배포

/etc/ssl/certs/ca-bundle.crt 파일을

Pod에 volume 형태로 배포.

해당 파일에는

iksoon.docker.com 접속용 CRT인증서와

notary-server 접속용 CRT인증서가 포함되어있음.

 

 

1. Portieris 가 정상적으로 배포되어 있는지 확인.

 

[명령어]

kubectl get all -n portieris

 

 

2. Notary Server와 Private Registry 접속 용 CRT 인증서 생성.

 

결국 따지고 보면 한가지의 방법과 다름없지만

작성자가 생성해본 2가지 방법을 모두 설명하겠음.

 

 

2.1. 직접 CRT 인증서 생성

root-ca.crt = Notary Server 인증서

server.crt = iksoon.docker.com Private Registry https 접근 용 인증서

2개의 파일을 하나로 합쳐서 인증서를 생성함.

 

[명령어]

cat root-ca.crt server.crt > notary_registry.crt

 

 

2.2. ca-bundle.crt 파일 사용법

 

centos 의 경우

/etc/pki/ca-trust/source/anchors 경로에

root-ca.crt = Notary Server 인증서

server.crt = iksoon.docker.com Private Registry https 접근 용 인증서

2개의 파일을 생성해놓음.

인증서 파일이 있는 상태에서

update-ca-trust 명령을하면 

해당 2개의 인증서가 

/etc/ssl/certs/ca-bundle.crt

파일에 추가됨.

ca-bundle.crt 파일에는 host가 사용하는 각종 인증서가 모두 포함되어있음

 

[ca-bundle.crt 파일 내용]

 

 

 

3. comfigMap 생성

 

portieris namespace에 상위에서 생성한 인증서 파일을 가지고있는 configMap 생성.

 

[configMap 생성 명령어]

 

(2.1. 방법으로 생성한 예)

kubectl -n portieris create cm iksoon-docker-crt --from-file=iksoon-crt=/경로/notary_registry.crt

 

(2.2. 방법으로 생성한 예)

kubectl -n portieris create cm iksoon-docker-crt --from-file=iksoon-crt=/etc/ssl/certs/ca-bundle.crt

 

[yaml 형식으로 생성 시 예제]

apiVersion: v1
kind: ConfigMap
metadata:
  name: iksoon-docker-crt
  namespace: portieris
data:
  iksoon-crt: |
    # Notary
    -----BEGIN CERTIFICATE-----
    MIIDTDCCAjSgAwIBAgIBATANBgk
    ~~~~ ca-bundle.crt 파일내용 ~~

 

 

4. portieris Container에 configMap을 Volume 으로 mount

 

[명령어]

kubectl edit deployment.apps/portieris -n portieris

 

편집창이 뜨면 아래와 같이 추가함.

        volumeMounts:
        - mountPath: /etc/certs
          name: portieris-certs
          readOnly: true
        - mountPath: /etc/ssl/certs
          name: iksoon-registry
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext:
        runAsUser: 1000060001
      serviceAccount: portieris
      serviceAccountName: portieris
      terminationGracePeriodSeconds: 30
      volumes:
      - name: portieris-certs
        secret:
          defaultMode: 420
          secretName: portieris-certs
      - configMap:
          items:
          - key: iksoon-crt
            path: certificates.crt
          name: iksoon-docker-crt
        name: iksoon-registry

 

 

5. Deployment 설정 적용 확인

 

[명령어]

kubectl get all -n portieris

명령으로 확인해보면

pod가 1개씩 update되고 있는것을 확인가능함.

 

 

6. imagePolicy 생성

 

[예제 imagePolicy.yaml 파일]

namespace = default (해당 namespace에만 정책이 적용됨.)

Private Registry = iksoon.docker.com:5000  (해당 registry에서만 image pull 가능)

trustServer = notary-server (구축한 notary 서버에서 인증을 받도록 설정)

apiVersion: securityenforcement.admission.cloud.ibm.com/v1beta1
kind: ImagePolicy
metadata:
  name: iksoon-custom
spec:
   repositories:
    - name: "iksoon.docker.com:5000/*"
      policy:
        trust:
          enabled: true
          trustServer: "https://notary-server:4443"

 

 

 

7. 결과 확인

 

[결과 확인 용도로 사용한 deployment.yaml 파일]

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iksoon-deployment
  labels:
    app: iksoon-tomcat
spec:
  replicas: 1
  selector:
    matchLabels:
      app: iksoon-pod
  template:
    metadata:
      labels:
        app: iksoon-pod
    spec:
      containers:
      - name: iksoon-tomcat
        image: iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.0 # 1.0.1 = 인증되어있음, 1.0.0 = 인증 안되어있음
        ports:
        - containerPort: 8080
      imagePullSecrets:
      - name: iksoon-secret-test

 

인증되어있는 1.0.1 version으로 배포

 

[배포 상태]

결과 : 성공적으로 배포됨

 

[Portieris log상태]

Portieris log 확인 참고 : kubectl logs -f   [생성된 portieris pod 3개중 1개] -n portieris 

예 : kubectl logs -f pod/portieris-7b4b7797dd-8brnw -n portieris 

I0914 07:02:02.449312       1 controller.go:65] Processing admission request for CREATE on iksoon-deployment
I0914 07:02:02.449536       1 controller.go:111] Getting policy for container image: iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.1   namespace: default
E0914 07:02:02.461154       1 controller.go:174] Secret iksoon-secret-test not defined for registry: iksoon.docker.com
I0914 07:02:02.461238       1 controller.go:220] policy.Trust {0xc00033556b [] https://notary-server:4443}
I0914 07:02:02.521942       1 trust.go:83] roleList length == 0, returning digest 4170f20639c49bdb5d773837527961ebcf3d4ae4aa920762cadb8bd5b58ca379
I0914 07:02:02.521960       1 controller.go:229] DCT digest: 4170f20639c49bdb5d773837527961ebcf3d4ae4aa920762cadb8bd5b58ca379
I0914 07:02:02.521970       1 controller.go:133] Mutation #: containers 0  Image name: iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.1
I0914 07:02:02.521978       1 controller.go:136] Mutated to: iksoon.docker.com:5000/domain_iksoon_tomcat@sha256:4170f20639c49bdb5d773837527961ebcf3d4ae4aa920762cadb8bd5b58ca379
I0914 07:02:02.522042       1 controller.go:142] Patch: { replace /spec/template/spec/containers/0/image iksoon.docker.com:5000/domain_iksoon_tomcat@sha256:4170f20639c49bdb5d773837527961ebcf3d4ae4aa920762cadb8bd5b58ca379}
I0914 07:02:02.522134       1 controller.go:161] Mutation patch: [{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"iksoon.docker.com:5000/domain_iksoon_tomcat@sha256:4170f20639c49bdb5d773837527961ebcf3d4ae4aa920762cadb8bd5b58ca379"}]
I0914 07:02:02.522144       1 controller.go:165] Allow
I0914 07:02:02.533448       1 controller.go:65] Processing admission request for CREATE on iksoon-deployment-7b67bb69bb
I0914 07:02:02.548616       1 controller.go:65] Processing admission request for CREATE on

 

 

[Notary Server log상태]

 

 

인증이 안되어있는 1.0.0 version으로 배포

 

[배포 상태]

결과 : 배포 안됨.

 

[참고] 

각 worker Node에 이미 해당 image가 pull 받아져있어도

Portieris에서 인증이 안되면 Pod 생성이 안됨.

 

[오류명]

Error from server: error when creating "1_deployment.yaml": admission webhook "trust.hooks.securityenforcement.admission.cloud.ibm.com" denied the request:

trust: policy denied the request: Deny "iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.0", failed to get content trust information: No valid trust data for 1.0.0

 

 

 

[Portieris log상태]

I0914 07:09:08.007714       1 controller.go:65] Processing admission request for CREATE on iksoon-deployment
I0914 07:09:08.007970       1 controller.go:111] Getting policy for container image: iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.0   namespace: default
E0914 07:09:08.019643       1 controller.go:174] Secret iksoon-secret-test not defined for registry: iksoon.docker.com
I0914 07:09:08.019666       1 controller.go:220] policy.Trust {0xc00061977b [] https://notary-server:4443}
I0914 07:09:08.095621       1 trust.go:64] GetAllTargetMetadataByName returned err: No valid trust data for 1.0.0
E0914 07:09:08.095651       1 responder.go:87] trust: policy denied the request: Deny "iksoon.docker.com:5000/domain_iksoon_tomcat:1.0.0", failed to get content trust information: No valid trust data for 1.0.0
I0914 07:09:08.095659       1 controller.go:150] Deny

 

 

[Notary Server log상태]

 

 

 

다른 Registry 에서 image pull 시도.

 

[Deployment 생성 시 사용한  image]

image: peksoon/iksoon_tomcat:1.0.6

iksoon.docker.com 에서 받지 않고 docker hub의 peksoon registry에서 배포 시도.

Error from server: error when creating "2_deployment.yaml": admission webhook "trust.hooks.securityenforcement.admission.cloud.ibm.com" denied the request:
Deny "peksoon/iksoon_tomcat:1.0.6", no matching repositories in the ImagePolicies

 

 

 

 

[Portieris log상태]

I0914 07:13:03.414095       1 controller.go:65] Processing admission request for CREATE on iksoon-deployment
I0914 07:13:03.416733       1 controller.go:111] Getting policy for container image: peksoon/iksoon_tomcat:1.0.6   namespace: default
E0914 07:13:03.424061       1 responder.go:87] Deny "peksoon/iksoon_tomcat:1.0.6", no matching repositories in the ImagePolicies
I0914 07:13:03.424115       1 controller.go:150] Deny

 

 

 

 

구축 완료.

 


 

 

 

또 다른 오류 1.

failed to get content trust information: dial tcp: lookup notary-server on 10.96.0.10:53: server misbehaving

 

오류명

Error from server: error when creating "1_deployment.yaml": admission webhook "trust.hooks.securityenforcement.admission.cloud.ibm.com" denied the request:

trust: policy denied the request: Deny "10.0.2.5:5000/peksoon_dct:1.0.0", failed to get content trust information: dial tcp: lookup notary-server on 10.96.0.10:53: server misbehaving

 

coreDNS log확인 결과

kubectl logs --follow pod/coredns-66bff467f8-chm8w -n kube-system

 

에러 원인

CoreDNS에서 unbound DNS에 정상적으로 Forwording이 안되고 있는 상황.

위 상황에서는

unbound ip 주소를 다른것을 적었었고, 

Unbound 설치 시 allowedIpRanges[0] 설정을 안했었음.

unbound 설치 시 allowedIpRanges[0] 설정을 안하면 default 로 

127.0.0.1/32만 접근 가능됨.

반드시 allowedIpRanges[0] 설정을 해줘야함.

 

해결책

ip를 unbound service object clusterIP를 넣어줬고

allowedIpRanges[0]설정 정상적으로 넣어줌.

 

 


 

 

 

또 다른 오류 2.

 

x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

 

상황

Kubernetes 1.18.3 version 에서는 정상적으로 동작이 됐었는데

Kubernetes 1.19.2 version으로 업데이트 하고 

Portieris 0.8.2 설치 후 적용하니 

Pod 배포 시 아래와 같이 오류가 발생.

 

오류 메세지

Error from server (InternalError): error when creating "1_deployment.yaml": Internal error occurred: failed calling webhook "trust.hooks.securityenforcement.admission.cloud.ibm.com": Post "https://portieris.portieris.svc:443/admit?timeout=30s": x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

 

원인

Kubernetes 1.19.2 update node 확인을 해보니

아래와 같은 사항이 있음

Kubernetes is now built with golang 1.15.0-rc.1.
The deprecated, legacy behavior of treating the CommonName field on X.509 serving certificates as a host name when no Subject Alternative Names are present is now disabled by default. It can be temporarily re-enabled by adding the value x509ignoreCN=0 to the GODEBUG environment variable. (#93264, @justaugustus) [SIG API Machinery, Auth, CLI, Cloud Provider, Cluster Lifecycle, Instrumentation, Network, Node, Release, Scalability, Storage and Testing]

기존에는 Wildcard 형식의 인증서도 사용가능했었지만

Kubernetes 1.19 versino 부터 golang 1.15.0-rc.1로 빌드되면서

인증서 사용 시 SAN(Subject Alternative Name)인증서를 사용해야함.

임시로 GODEBUG=x509ignoreCN=0 환경변수를 설정해서

Wildcard 인증서도 사용할 수 있지만 말 그대로 임시 대처법임.

 

 

해결책

인증서를 SAN형식으로 생성해줘야함.

 

portieris 인증서를 SAN형식으로 변경하는법 [ Portieris 0.8.2 ]

1. gencerts 파일을 수정해줘야함.

 

[명령어]

vi ~/portieris/helm/portieris/gencerts

 

원본의 경우 인증서 생성 부분이 아래와 같음.

해당 부분을 보아하니 default로 생성되던 인증서는 wildcard 형식의 인증서임.

cat > "$CERT_DIR"/server.conf << EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
EOF

 

 

Wildcard 형식의 인증서를 SAN형식 인증서로 변경하기 위해

다음과 같이 변경해줌.

cat > "$CERT_DIR"/server.conf << EOF
[req]
default_bits       = 2048
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
countryName                = KR
localityName               = Locality Name (eg, city)
organizationName           = IKSOON
commonName                 = Portieris
[ v3_req ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = portieris.portieris.svc
DNS.2   = trust.hooks.securityenforcement.admission.cloud.ibm.com
EOF 

SAN 형식으로 인증서를 생성하는데 Portieris 의 경우 

Portieris Webhook과 IBM 에 연결 인증을 하기 위해

아래 두개의 DNS를 추가해줘야함.

 

portieris.portieris.svc

trust.hooks.securityenforcement.admission.cloud.ibm.com

 

 

2. gencerts 파일 실행해서 인증서 생성.

[명령어]

./portieris/helm/portieris/gencerts

 

3. Portieris 설치

[명령어]

helm install portieris --create-namespace --namespace portieris helm/portieris

 

해결완료.

 

 


또 다른 오류 3.

 

spec.versions: Invalid value: []apiextensions.CustomResourceDefinitionVersion(nil): must have exactly one version marked as storage version

 

상황

Kubernetes 1.18.3 version 에서는 정상적으로 동작이 됐었는데

Kubernetes 1.20 version으로 업데이트 하고 

Portieris 0.9.5 설치 후 적용하니 

crd 생성 시 아래와 같이 오류가 발생.

 

[오류 메세지]

Error: failed to install CRD crds/crds.yaml: CustomResourceDefinition.apiextensions.k8s.io "imagepolicies.securityenforcement.admission.cloud.ibm.com" is invalid: [spec.versions: Invalid value: []apiextensions.CustomResourceDefinitionVersion(nil): must have exactly one version marked as storage version, status.storedVersions: Invalid value: []string(nil): must have at least one stored version]

 

원인

Kubernetes 1.20 update node 확인을 해보니

이제 crd 생성 시 v1beta1 versiond을 지원하지 않음.

실제로 1.20에서 v1beta1을 사용하면 아래와 같은 오류가 나옴.

v1 version CRD를 사용해야함

 

 

해결책

versiond을 v1으로 설정함.

그리고 versions 설정을 명시하고

schema를 추가해야함.

현재 portieris 9.5.0 version에서는 

schema를 명시하지 않고 v1beta1를 사용하고 있어서

imagepolicy를 보고 schema정보를 직접 유추해서 추가하여 문제를 해결함.

아래의 imagepolicy, clusterimagepolicy는 본인이 직접 생성한 crd임.

~/portieris/helm/portieris/crds directory에 있는

crds.yaml 파일을 수정

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: imagepolicies.securityenforcement.admission.cloud.ibm.com
  labels:
    app: portieris
spec:
  group: securityenforcement.admission.cloud.ibm.com
  names:
    kind: ImagePolicy
    listKind: ImagePolicyList
    plural: imagepolicies
    singular: imagepolicy
  scope: Namespaced
  versions:
    - name: v1beta1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                repositories:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      policy:
                        type: object
                        properties:
                          trust:
                            type: object
                            properties:
                              enabled:
                                type: boolean
                              trustServer:
                                type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: clusterimagepolicies.securityenforcement.admission.cloud.ibm.com
  labels:
    app: portieris
spec:
  group: securityenforcement.admission.cloud.ibm.com
  names:
    kind: ClusterImagePolicy
    listKind: ClusterImagePolicyList
    plural: clusterimagepolicies
    singular: clusterimagepolicy
  scope: Cluster
  versions:
    - name: v1beta1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                repositories:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      policy:
                        type: object
                        properties:
                          trust:
                            type: object
                            properties:
                              enabled:
                                type: boolean
                              trustServer:
                                type: string

해당 crd는 

portiers에서 제공하고 있는 다양한 imagepolicy, clusterimagepolicy 예제중

아래의 예제만 지원하는 crd임.

 

[예제 ImagePolicy.yaml]

apiVersion: securityenforcement.admission.cloud.ibm.com/v1beta1
kind: ImagePolicy
metadata:
  name: iksoon-custom
  namespace: iksoon-ns
spec:
   repositories:
    - name: "iksoon.docker.com:5000/*"
      policy:
        trust:
          enabled: true
          trustServer: "https://notary-server:4443"

 

 

 

 

 

 

 

 

 


제 글을 복사할 시 출처를 명시해주세요.
글에 오타, 오류가 있다면 댓글로 알려주세요! 바로 수정하겠습니다!


 

 

 

 

 


 

 

 

[참고]

https://github.com/IBM/portieris

https://github.com/IBM/portieris/blob/master/POLICIES.md

https://cloud.ibm.com/docs/Registry?topic=Registry-security_enforce#assign_user_policy

https://www.youtube.com/watch?v=JK70k_B87mw&t=1s

 

[no such host 에러 해결 참고]

https://medium.com/@zhimin.wen/running-knative-on-on-premise-kubernetes-cluster-ibm-cloud-private-4227ee322aa0

https://hub.helm.sh/charts/stable/unbound

 

[unbound DNS 참고]

https://hub.helm.sh/charts/stable/unbound/0.1.2

 

[coreDNS 참고 ]

https://kubernetes.io/ko/docs/tasks/administer-cluster/dns-custom-nameservers/

https://docs.microsoft.com/ko-kr/azure/aks/coredns-custom

https://coredns.io/manual/what/

https://kubernetes.io/blog/2018/07/10/coredns-ga-for-kubernetes-cluster-dns/

https://jonnung.dev/kubernetes/2020/05/11/kubernetes-dns-about-coredns/

https://dev.to/robbmanes/running-coredns-as-a-dns-server-in-a-container-1d0

 

 

 

 

 

 

반응형