Kubernetes image인증 - Portieris
(Kubernetes DCT 연동)
[Container image 인증 관련 글 목록]
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 주소 ]
IP : 10.0.2.5
[ K8s에서 Private Registry 접속 설정완료. ]
/etc/pki/ca-trust/source/anchors 경로에 crt인증서가 있음.
root-ca.crt = Notary Server 인증서
server.crt = iksoon.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://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
'Kubernetes > Kubernetes 보안' 카테고리의 다른 글
Portieris (v0.12.2) (0) | 2022.02.23 |
---|---|
Kubernetes ImagePolicyWebhook (0) | 2021.04.05 |
Kubernetes 인증 ( Proxy ) (0) | 2020.08.29 |
Kubernetes 인증 (Webhook 외부 인증 LDAP) (0) | 2020.08.29 |
Kubernetes 인증 ( Webhook 외부 인증 연동 ) (0) | 2020.08.29 |