Kubernetes 이야기

Kubernetes에서 Connaisseur 를 사용하여 이미지 서명 검증하기 본문

Kubernetes/보안

Kubernetes에서 Connaisseur 를 사용하여 이미지 서명 검증하기

kmaster 2022. 2. 22. 20:30
반응형

Connaisseur 

Connaisseur는 컨테이너 이미지 서명 확인을 위한 Kubernetes admission controller 이다.

 

Cosign (https://github.com/sigstore/cosign) 을 사용하여 이미지 서명을 하였는데 서명된 이미지를 Kubernetes Pod로 실행 시 검증을 하기 위해서 Connaisseur을 사용한다.

 

Connaisseur는 Kubernetes 클러스터에서 컨테이너 이미지의 무결성과 출처를 보장한다. 이미지 검증 결과에 따라 해당 요청을 수락하거나 거부할 수 있다.

 

Connaisseur는 아래의 이미지 서명 솔루션과 연동을 목표로 하고 있다.

Notary V1 / Docker Content Trust
Sigstore / Cosign
Notary V2 (예정)

 

주요기능

 

  • 감지 모드 : 경고하지만 잘못된 이미지를 차단하지 않는다.
  • 네임스페이스 유효성 검사 : 전용 네임스페이스로 유효성 검사를 제한한다.
  • 알림 : 확인 결과에 따라 알림을 보낸다.
  • 자동 하위 승인 : Kubernetes 하위 리소스의 승인 구성

설치

 

helm 설치를 위해 helm chart가 저장된 git 소스를 내려받는다.

git clone https://github.com/sse-secure-systems/connaisseur.git

 

helm 설치 전 value를 설정한다.

...

validators:
  # static validator that allows each image
  - name: allow
    type: static
    approve: true
  # static validator that denies each image
  - name: deny
    type: static
    approve: false
  # the `default` validator is used if no validator is specified in image policy
  - name: custom-validator
    type: cosign  # or other supported validator (e.g. "cosign")
    trust_roots:
    - name: ghcr
      key: k8s://image-sign/cosignkey
        
...

 

Policy 정책을 추가한다.

...

policy:
  - pattern: "ghcr.io/kmaster8/*:*"
    validator: custom-validator
    with:
      trust_root: ghcr

...

 

모든 NS가 아닌 특정한 NS만 이미지 검증을 하고 싶은 경우가 있을 것이다. 이때는 아래의 옵션을 적용한다.

...

namespacedValidation:
  enabled: true
  mode: validate  # 'ignore' or 'validate'

...

위와 같이 하면 검사하고자 하는 NS에 securesystemsengineering.connaisseur/webhook=validate 라벨이 있는 Namepsace만 검사한다.

 

 

이제, Helm으로 설치를 진행한다.

helm install connaisseur helm --atomic --create-namespace --namespace connaisseur

 

이제 pod상태를 확인해 보자.

# kubectl get po -n connaisseur
NAME                                      READY   STATUS    RESTARTS   AGE
connaisseur-deployment-5b586b5f6b-bwckl   1/1     Running   0          21s
connaisseur-deployment-5b586b5f6b-gbxv7   1/1     Running   0          21s
connaisseur-deployment-5b586b5f6b-jlhzb   1/1     Running   0          21s

 

Kubernetes 설정

 

이미지 서명 검사를 하고자 하는 Namespace에 라벨을 추가해 보자.

 

# kubectl create ns image-test

# kubectl label namespaces image-test securesystemsengineering.connaisseur/webhook=validate --overwrite=true

 

이제 이미지 서명이 없는 container를 kubernetes에서 실행해 보자

# kubectl run demo --image=docker.io/securesystemsengineering/testimage:unsigned -n image-test
Error from server: admission webhook "connaisseur-svc.connaisseur.svc" denied the request: unknown error. please check the logs.

 

반대로 label이 없는 default NS에서 실행해 보자.

# kubectl run demo --image=docker.io/securesystemsengineering/testimage:unsigned
pod/demo created

 

위와 같이 Namespace에 "securesystemsengineering.connaisseur/webhook=validate" 라벨이 없는 Namespace에서는 이미지 서명 검사를 하지 않는 것을 볼 수 있다.

 

그 다음으로 이미지 서명이 완료된 이미지를 kubernetes에서 실행해 보자

# kubectl run demo --image=docker.io/securesystemsengineering/testimage:signed -n image-test
pod/demo created

 

ghcr.io 연동 테스트

 

이제 ghcr.io에 저장된 container도 이미지 서명 검사를 잘 하는지 확인해 보자.

현재 ghcr.io에는 아래의 두가지 이미지가 존재한다.

 

  • ghcr.io/kmaster8/image-sign
  • ghcr.io/kmaster8/image-nosign

 

이제 각각 배포해 보자.

 

# kubectl run demo --image=ghcr.io/kmaster8 -n image-test
Error from server: admission webhook "connaisseur-svc.connaisseur.svc" denied the request: Unexpected Cosign exception for image "ghcr.io/kmaster8/image-sign:latest": Error: loading public key: checking if secret exists: secrets "cosignkey" is forbidden: User "system:serviceaccount:connaisseur:connaisseur-serviceaccount" cannot get resource "secrets" in API group "" in the namespace "image-sign"
main.go:46: error during command execution: loading public key: checking if secret exists: secrets "cosignkey" is forbidden: User "system:serviceaccount:connaisseur:connaisseur-serviceaccount" cannot get resource "secrets" in API group "" in the namespace "image-sign"

 

위의 에러는 system:serviceaccount:connaisseur:connaisseur-serviceaccount 서비스 계정이 image-sign namespace의 secret 조회 권한이 없어서 발생하는 오류이다. 

 

connaisseur cluster role에 secrets 권한을 추가한다. ( 권한을 주기 싫으면 values.yaml에서 secret 대신 public key를 직접 입력해도 된다.

 

이제 다시 실행해 보자

# kubectl run demo --image=ghcr.io/kmaster8/image-sign -n image-test
pod/demo created

 

정상적으로 실행되는 것을 확인하였고, 이제 다시 이미지 서명이 없는 이미지를 실행해 보자

# kubectl run demo --image=ghcr.io/kmaster8/image-nosign -n image-test
Error from server: admission webhook "connaisseur-svc.connaisseur.svc" denied the request: No trust data for image "ghcr.io/kmaster8/image-nosign:latest".

 

 

반응형
Comments