이미지 및 비이미지 아티팩트 서명 확인

이미지 서명을 확인하여 배치하기 전에 CI (Continuous Integration) 파이프라인에 빌드된 이미지의 무결성을 유지합니다.

시작하기 전에

이미지 인증 작업을 시작하기 전에 다음 필수 조건이 충족되었는지 확인하십시오.

  • GPG 공개 키가 있어야 합니다. GPG키 생성에 대한 도움말은 문서 를 참조하십시오.
  • 기본 64인코딩 GPG 공개 키를 사용하여 환경 변수 code-signing-certificate 를 추가해야 합니다.
  • 검증 과정에서 컨테이너 이미지에 액세스하려면 레지스트리 자격 증명을 구성해야 합니다( ‘레지스트리 자격 증명 구성’ 참조).

이미지 확인

prod-verify-artifact 단계에서는 Continuous Delivery 파이프라인에서 이미지의 서명을 확인합니다. 이 스테이지는 다음 단계를 수행합니다.

  1. 사용자가 제공하는 인코딩된 GPG 공개 키를 임시 파일로 디코딩합니다.

  2. 공개 키를 사용하여 Docker 컨테이너 정책 (/etc/containers/policy.json) 을 작성합니다.

     {
       "default": [
         {
           "type": "reject"
         }
       ],
       "transports": {
         "docker-daemon": {
           "": [
             {
               "type": "reject"
             }
           ]
         },
         "docker": {
           "": [
             {
               "type": "signedBy",
               "keyType": "GPGKeys",
               "keyPath": "/tmp/GPGPublicKey"
             }
           ]
         }
       }
     }
    
  3. Skopeo 를 사용하여 컨테이너 정책이 있는 이미지를 가져와서 각 아티팩트의 아티팩트 목록을 검색합니다.

        skopeo copy docker://"${image}" dir:"${tmp_sign_dir}" --src-creds iamapikey:"${ibmcloud_api_key}"
    

사용자가 제공한 공개 키로 서명이 유효하고 확인되면 이미지 가져오기에 성공합니다.

검증을 위한 레지스트리 자격 증명 설정

컨테이너 이미지 서명을 검증할 때, 파이프라인은 컨테이너 레지스트리에 인증하고 서명된 이미지에 액세스하기 위해 자격 증명이 필요합니다. DevSecOps 파이프라인은 런타임 시 동적 자격 증명 확인을 지원하므로, 자동 대체 메커니즘을 통해 다양한 방식으로 자격 증명을 구성할 수 있습니다.

인증 정보 확인 계층 구조

파이프라인은 런타임 시 다음 계층 구조를 사용하여 사용자 이름과 API 키 자격 증명을 동적으로 해결합니다:

API 키 확인 순서:

  1. 네임스페이스 전용 API 키: signing-token-apikey-{registry}-{namespace} (비밀 키)
  2. 레지스트리 전용 API 키: signing-token-apikey-{registry} (비밀번호)
  3. Docker JSON 구성 파일: signing-dockerconfigjson (비밀번호)
  4. ICR 전용 대체 방안:
    • ciso-ibmcloud-api-key (비밀)
    • ibmcloud-api-key (비밀)

사용자 이름 확인 순서:

  1. 네임스페이스별 사용자 이름: signing-token-username-{registry}-{namespace} (환경 변수)
  2. 레지스트리 전용 사용자 이름: signing-token-username-{registry} (환경 변수)
  3. 기본값: iamapikey (사용자 이름이 설정되지 않은 경우)

여기서:

  • {registry} 레지스트리 호스트 이름입니다(예: us.icr.io, de.icr.io)
  • {namespace} 슬래시와 점(.)을 밑줄(_)로 대체한 전체 네임스페이스 경로입니다(예: my_namespace_path)

네임스페이스별 자격 증명 구성

세분화된 액세스 제어를 위해 레지스트리 네임스페이스별로 고유한 자격 증명을 구성할 수 있습니다:

API 키 (비밀 키): signing-token-apikey-{registry}-{namespace}

사용자 이름 (환경 변수): signing-token-username-{registry}-{namespace}

예시: 이미지의 경우 us.icr.io/my-namespace/my-app:latest

  • registry: us.icr.io
  • 네임스페이스: my-namespace
  • API 키 비밀번호: signing-token-apikey-us.icr.io-my_namespace
  • 사용자 이름 환경 변수: signing-token-username-us.icr.io-my_namespace
  • 사용자 이름을 지정하지 않으면 기본값은 다음과 같습니다: iamapikey

레지스트리 전용 자격 증명 구성

레지스트리의 모든 네임스페이스에 걸쳐 더 광범위한 접근 권한을 부여하려면:

API 키 (비밀 키): signing-token-apikey-{registry}

사용자 이름 (환경 변수): signing-token-username-{registry}

: 다음의 모든 이미지에 대해 us.icr.io

  • API 키 비밀번호: signing-token-apikey-us.icr.io
  • 사용자 이름 환경 변수: signing-token-username-us.icr.io
  • 사용자 이름을 지정하지 않으면 기본값은 다음과 같습니다: iamapikey

Docker 구성 JSON 설정

여러 레지스트리의 인증 정보가 포함된 base64-encoded Docker 구성 JSON 파일을 제공할 수 있습니다:

비밀 이름: signing-dockerconfigjson

형식: Base64-encoded JSON ( Docker 의 config.json 형식과 일치함):

{
  "auths": {
    "us.icr.io": {
      "username": "iamapikey",
      "password": "your-api-key"
    },
    "us.icr.io/my-namespace": {
      "username": "iamapikey",
      "password": "namespace-specific-key"
    }
  }
}

파이프라인은 가장 구체적인 경로부터 우선적으로 일치시키며, 이를 통해 Docker 구성 내에서 네임스페이스 수준의 재정의가 가능합니다.

구성 예

us.icr.io/production/my-app:v1.0.0 이미지의 경우:

옵션 1: 네임스페이스별 (프로덕션 환경에서 권장)

  • API 키 비밀번호: signing-token-apikey-us.icr.io-production = your-namespace-api-key
  • 사용자 이름 환경 변수 (선택 사항): signing-token-username-us.icr.io-production = iamapikey
  • 사용자 이름을 지정하지 않으면 기본값은 iamapikey

옵션 2: 레지스트리 전체

  • API 키 비밀번호: signing-token-apikey-us.icr.io = your-registry-api-key
  • 사용자 이름 환경 변수 (선택 사항): signing-token-username-us.icr.io = iamapikey
  • 사용자 이름을 지정하지 않으면 기본값은 iamapikey

옵션 3: Docker 구성 JSON

  • 비밀: signing-dockerconfigjson = base64-encoded-docker-config
  • 사용자 이름은 Docker 설정 JSON 파일에서 추출됩니다

옵션 4: IBM Cloud 기본값 (ICR의 경우 자동)

  • API 키 비밀번호: ibmcloud-api-key = your-ibmcloud-api-key
  • 사용자 이름은 기본적으로 iamapikey

비이미지 아티팩트 확인

DevSecOps 파이프라인에서는 서명된 아티팩트의 서명이 검증 대상이 됩니다. 이 절에서는 아티팩트 검증을 진행하기 전에 사용자가 충족해야 하는 전제조건을 개괄적으로 설명합니다.

시작하기 전에

이미지 검증에 대해 작업하기 전에 다음 전제조건이 있는지 확인하십시오.

  1. 검증 프로세스를 사용하도록 파이프라인 구성을 수정하십시오. .pipeline-config.yaml 파일에 다음 코드 조각을 추가하세요.

    verify-artifact:
      image: icr.io/continuous-delivery/pipeline/image-signing:1.0.0@sha256:e9d8e354668ba3d40be2aaee08298d2aa7f0e1c8a1829cca4094ec93830e3e6a
      image_pull_policy: IfNotPresent
      abort_on_failure: false
      dind: true
      script: |
        #!/usr/bin/env bash
        source /opt/commons/verify-artifact/verify_non_image_artifact.sh
    
  2. 아티팩트를 다운로드하여 파이프라인 런타임에 저장하십시오.

    verify-artifact 단계를 호출하기 전에 필요한 아티팩트를 다운로드하여 코코아 런타임에 저장하십시오. 기본적으로 ‘ list_artifacts ’ 컬렉션에 나열된 모든 아티팩트는 검증됩니다. skip-sign-artifact-type 텍스트 속성을 사용하여 지정된 아티팩트 유형(예: log, report, documentation)에 대한 이미지 서명 검증을 건너뜁니다. 다음 예제 코드는 Cloud Object Storage 에서 아티팩트를 다운로드하여 Cocoa 런타임에 저장하는 방법을 보여줍니다:

    #!/usr/bin/env bash
    
    export SECRET_PATH="/config/ibmcloud-api-key"
    . "${ONE_PIPELINE_PATH}"/iam/get_token
    
    SKIP_SIGN_ARTIFACTS_TYPE="$(get_env skip-sign-artifact-type "")"
    IFS=';' read -ra ARTIFACT_LIST <<<"$SKIP_SIGN_ARTIFACTS_TYPE"
    
    list_artifacts | while IFS= read -r artifact; do
    
       type="$(load_artifact "$artifact" "type")"
    
       if [[ ! "${ARTIFACT_LIST[@]}" =~ "$type" ]] && [[ "$type" != "image" ]]; then
    
          inventory_entry="$(load_artifact "$artifact" "inventory-entry")"
          inventory_entry=${inventory_entry///artifacts/$WORKSPACE}
          artifact_url=$(jq -r .'app_artifacts.artifact_url' ${inventory_entry})
          echo "downloading the artifact  ${artifact_url}"
          curl -H "Authorization: bearer ${IAM_ACCESS_TOKEN}" --output outputfile ${artifact_url}
          save_file "${artifact}" outputfile
    
       fi
    done
    

아티팩트 확인

아티팩트 확인 프로세스에서 사용자 제공 GPG 공개 키를 GPG키 링으로 가져옵니다. list_artifacts 콜렉션에 나열된 모든 아티팩트가 확인됩니다. 이 스테이지는 자원 명세에서 서명을 검색하려고 시도하고 다음 확인을 수행합니다.

gpg --verify  "${signature}" "${artifactName}"

제공된 공개 키를 사용하여 서명이 올바르고 확인된 경우 스테이지는 증거를 기록하고 단계를 성공으로 표시합니다.