InfoGrab Docs

튜토리얼: 빌드 출처 데이터로 컨테이너 이미지에 주석 달기

요약

주석은 빌드 프로세스에 대한 유용한 메타데이터를 제공합니다. 이 튜토리얼은 Cosign을 사용하여 컨테이너 이미지를 빌드, 서명 및 주석 추가 프로세스를 자동화하는 GitLab 파이프라인을 설정하는 방법을 설명합니다.

주석은 빌드 프로세스에 대한 유용한 메타데이터를 제공합니다. 이 정보는 감사와 추적에 사용됩니다. 보안 사고 발생 시, 상세한 출처 데이터가 있으면 조사 및 해결 프로세스를 상당히 빠르게 진행할 수 있습니다.

이 튜토리얼은 Cosign을 사용하여 컨테이너 이미지를 빌드, 서명 및 주석 추가 프로세스를 자동화하는 GitLab 파이프라인을 설정하는 방법을 설명합니다. .gitlab-ci.yml 파일을 구성하여 Docker 이미지를 빌드, 푸시, 서명하고 GitLab 컨테이너 레지스트리에 푸시할 수 있습니다.

컨테이너 이미지에 주석을 달려면:

  1. 이미지 및 서비스 이미지 설정.
  2. CI/CD 변수 정의.
  3. OIDC 토큰 준비.
  4. 컨테이너 준비.
  5. 이미지 빌드 및 푸시.
  6. Cosign으로 이미지 서명.
  7. 서명 및 주석 확인.

모든 내용을 합치면 .gitlab-ci.yml은 이 튜토리얼 끝에 제공된 샘플 구성과 비슷해야 합니다.

시작하기 전에#

다음이 필요합니다:

이미지 및 서비스 이미지 설정#

.gitlab-ci.yml 파일에서 docker:cli 이미지를 사용하고 Docker-in-Docker 서비스를 활성화하여 CI/CD 잡 내에서 Docker 명령어를 실행할 수 있도록 합니다.

build_and_sign:
  stage: build
  image: docker:cli
  services:
    - docker:dind  # Enable Docker-in-Docker service to allow Docker commands inside the container

CI/CD 변수 정의#

GitLab CI/CD 사전 정의 변수를 사용하여 이미지 태그 및 URI에 대한 변수를 정의합니다.

variables:
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA  # Use the commit short SHA as the image tag
  IMAGE_URI: $CI_REGISTRY_IMAGE:$IMAGE_TAG  # Construct the full image URI with the registry, project path, and tag
  COSIGN_YES: "true"  # Automatically confirm actions in Cosign without user interaction
  FF_SCRIPT_SECTIONS: "true"  # Enables GitLab's CI script sections for better multi-line script output

OIDC 토큰 준비#

Cosign을 이용한 키리스 서명을 위한 OIDC 토큰을 설정합니다.

id_tokens:
  SIGSTORE_ID_TOKEN:
    aud: sigstore  # Provide an OIDC token for keyless signing with Cosign

컨테이너 준비#

.gitlab-ci.yml 파일의 before_script 섹션에서:

  • Cosign 및 jq(JSON 처리용) 설치: apk add --no-cache cosign jq
  • CI/CD 잡 토큰을 사용한 GitLab 컨테이너 레지스트리 로그인 활성화: docker login -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" "$CI_REGISTRY"

파이프라인은 필요한 환경을 설정하여 시작됩니다.

이미지 빌드 및 푸시#

.gitlab-ci.yml 파일의 script 섹션에 다음 명령어를 입력하여 Docker 이미지를 빌드하고 GitLab 컨테이너 레지스트리에 푸시합니다.

- docker build --pull -t "$IMAGE_URI" .
- docker push "$IMAGE_URI"

이 명령어는 현재 디렉토리의 Dockerfile을 사용하여 이미지를 생성하고 레지스트리에 푸시합니다.

Cosign으로 이미지 서명#

이미지를 빌드하여 GitLab 컨테이너 레지스트리에 푸시한 후, Cosign을 사용하여 이미지에 서명합니다.

.gitlab-ci.yml 파일의 script 섹션에 다음 명령어를 입력합니다:

- IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_URI")
- |
  cosign sign "$IMAGE_DIGEST" \
    --registry-referrers-mode oci-1-1 \
    --annotations "com.gitlab.ci.user.name=$GITLAB_USER_NAME" \
    --annotations "com.gitlab.ci.pipeline.id=$CI_PIPELINE_ID" \
    # Additional annotations removed for readability
    --annotations "tag=$IMAGE_TAG"

이 단계에서는 이미지 다이제스트를 가져옵니다. 그런 다음 Cosign을 사용하여 이미지에 서명하고 여러 주석을 추가합니다.

서명 및 주석 확인#

이미지에 서명한 후에는 서명과 추가된 주석을 확인하는 것이 중요합니다.

.gitlab-ci.yml 파일에 cosign verify 명령어를 사용하는 확인 단계를 포함합니다:

- |
  cosign verify \
    --annotations "tag=$IMAGE_TAG" \
    --certificate-identity "$CI_PROJECT_URL//.gitlab-ci.yml@refs/heads/$CI_COMMIT_REF_NAME" \
    --certificate-oidc-issuer "$CI_SERVER_URL" \
    "$IMAGE_URI" | jq .

확인 단계는 이미지에 첨부된 출처 데이터가 올바르고 변조되지 않았음을 보장합니다. cosign verify 명령어는 서명을 확인하고 주석을 검사합니다. 출력에는 서명 프로세스 중 이미지에 추가한 모든 주석이 표시됩니다.

출력에서 다음을 포함한 이전에 추가된 모든 주석을 확인할 수 있습니다:

  • GitLab 사용자 이름
  • 파이프라인 ID 및 URL
  • 잡 ID 및 URL
  • 커밋 SHA 및 참조 이름
  • 프로젝트 경로
  • 이미지 소스 및 리비전

이러한 주석을 확인하면 이미지의 출처 데이터가 그대로 있고 빌드 프로세스를 기반으로 예상한 내용과 일치하는지 확인할 수 있습니다.

.gitlab-ci.yml 구성 예시#

이전 모든 단계를 따르면 .gitlab-ci.yml 파일은 다음과 같아야 합니다:

stages:
  - build

build_and_sign:
  stage: build
  image: docker:cli
  services:
    - docker:dind  # Enable Docker-in-Docker service to allow Docker commands inside the container
  variables:
    IMAGE_TAG: $CI_COMMIT_SHORT_SHA  # Use the commit short SHA as the image tag
    IMAGE_URI: $CI_REGISTRY_IMAGE:$IMAGE_TAG  # Construct the full image URI with the registry, project path, and tag
    COSIGN_YES: "true"  # Automatically confirm actions in Cosign without user interaction
    FF_SCRIPT_SECTIONS: "true"  # Enables GitLab's CI script sections for better multi-line script output
  id_tokens:
    SIGSTORE_ID_TOKEN:
      aud: sigstore  # Provide an OIDC token for keyless signing with Cosign
  before_script:
    - apk add --no-cache cosign jq  # Install Cosign (mandatory) and jq (optional)
    - docker login -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" "$CI_REGISTRY"  # Log in to the Docker registry using GitLab CI token
  script:
    # Build the Docker image using the specified tag and push it to the registry
    - docker build --pull -t "$IMAGE_URI" .
    - docker push "$IMAGE_URI"

    # Retrieve the digest of the pushed image to use in the signing step
    - IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_URI")

    # Sign the image using Cosign with annotations that provide metadata about the build and tag annotation to allow verifying
    # the tag->digest mapping (https://github.com/sigstore/cosign?tab=readme-ov-file#tag-signing)
    - |
      cosign sign "$IMAGE_DIGEST" \
        --registry-referrers-mode oci-1-1 \
        --annotations "com.gitlab.ci.user.name=$GITLAB_USER_NAME" \
        --annotations "com.gitlab.ci.pipeline.id=$CI_PIPELINE_ID" \
        --annotations "com.gitlab.ci.pipeline.url=$CI_PIPELINE_URL" \
        --annotations "com.gitlab.ci.job.id=$CI_JOB_ID" \
        --annotations "com.gitlab.ci.job.url=$CI_JOB_URL" \
        --annotations "com.gitlab.ci.commit.sha=$CI_COMMIT_SHA" \
        --annotations "com.gitlab.ci.commit.ref.name=$CI_COMMIT_REF_NAME" \
        --annotations "com.gitlab.ci.project.path=$CI_PROJECT_PATH" \
        --annotations "org.opencontainers.image.source=$CI_PROJECT_URL" \
        --annotations "org.opencontainers.image.revision=$CI_COMMIT_SHA" \
        --annotations "tag=$IMAGE_TAG"

    # Verify the image signature using Cosign to ensure it matches the expected annotations and certificate identity
    - |
      cosign verify \
        --annotations "tag=$IMAGE_TAG" \
        --certificate-identity "$CI_PROJECT_URL//.gitlab-ci.yml@refs/heads/$CI_COMMIT_REF_NAME" \
        --certificate-oidc-issuer "$CI_SERVER_URL" \
        "$IMAGE_URI" | jq .  # Use jq to format the verification output for easier readability

튜토리얼: 빌드 출처 데이터로 컨테이너 이미지에 주석 달기

원문 보기
요약

주석은 빌드 프로세스에 대한 유용한 메타데이터를 제공합니다. 이 튜토리얼은 Cosign을 사용하여 컨테이너 이미지를 빌드, 서명 및 주석 추가 프로세스를 자동화하는 GitLab 파이프라인을 설정하는 방법을 설명합니다.

주석은 빌드 프로세스에 대한 유용한 메타데이터를 제공합니다. 이 정보는 감사와 추적에 사용됩니다. 보안 사고 발생 시, 상세한 출처 데이터가 있으면 조사 및 해결 프로세스를 상당히 빠르게 진행할 수 있습니다.

이 튜토리얼은 Cosign을 사용하여 컨테이너 이미지를 빌드, 서명 및 주석 추가 프로세스를 자동화하는 GitLab 파이프라인을 설정하는 방법을 설명합니다. .gitlab-ci.yml 파일을 구성하여 Docker 이미지를 빌드, 푸시, 서명하고 GitLab 컨테이너 레지스트리에 푸시할 수 있습니다.

컨테이너 이미지에 주석을 달려면:

  1. 이미지 및 서비스 이미지 설정.
  2. CI/CD 변수 정의.
  3. OIDC 토큰 준비.
  4. 컨테이너 준비.
  5. 이미지 빌드 및 푸시.
  6. Cosign으로 이미지 서명.
  7. 서명 및 주석 확인.

모든 내용을 합치면 .gitlab-ci.yml은 이 튜토리얼 끝에 제공된 샘플 구성과 비슷해야 합니다.

시작하기 전에#

다음이 필요합니다:

이미지 및 서비스 이미지 설정#

.gitlab-ci.yml 파일에서 docker:cli 이미지를 사용하고 Docker-in-Docker 서비스를 활성화하여 CI/CD 잡 내에서 Docker 명령어를 실행할 수 있도록 합니다.

build_and_sign:
  stage: build
  image: docker:cli
  services:
    - docker:dind  # Enable Docker-in-Docker service to allow Docker commands inside the container

CI/CD 변수 정의#

GitLab CI/CD 사전 정의 변수를 사용하여 이미지 태그 및 URI에 대한 변수를 정의합니다.

variables:
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA  # Use the commit short SHA as the image tag
  IMAGE_URI: $CI_REGISTRY_IMAGE:$IMAGE_TAG  # Construct the full image URI with the registry, project path, and tag
  COSIGN_YES: "true"  # Automatically confirm actions in Cosign without user interaction
  FF_SCRIPT_SECTIONS: "true"  # Enables GitLab's CI script sections for better multi-line script output

OIDC 토큰 준비#

Cosign을 이용한 키리스 서명을 위한 OIDC 토큰을 설정합니다.

id_tokens:
  SIGSTORE_ID_TOKEN:
    aud: sigstore  # Provide an OIDC token for keyless signing with Cosign

컨테이너 준비#

.gitlab-ci.yml 파일의 before_script 섹션에서:

  • Cosign 및 jq(JSON 처리용) 설치: apk add --no-cache cosign jq
  • CI/CD 잡 토큰을 사용한 GitLab 컨테이너 레지스트리 로그인 활성화: docker login -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" "$CI_REGISTRY"

파이프라인은 필요한 환경을 설정하여 시작됩니다.

이미지 빌드 및 푸시#

.gitlab-ci.yml 파일의 script 섹션에 다음 명령어를 입력하여 Docker 이미지를 빌드하고 GitLab 컨테이너 레지스트리에 푸시합니다.

- docker build --pull -t "$IMAGE_URI" .
- docker push "$IMAGE_URI"

이 명령어는 현재 디렉토리의 Dockerfile을 사용하여 이미지를 생성하고 레지스트리에 푸시합니다.

Cosign으로 이미지 서명#

이미지를 빌드하여 GitLab 컨테이너 레지스트리에 푸시한 후, Cosign을 사용하여 이미지에 서명합니다.

.gitlab-ci.yml 파일의 script 섹션에 다음 명령어를 입력합니다:

- IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_URI")
- |
  cosign sign "$IMAGE_DIGEST" \
    --registry-referrers-mode oci-1-1 \
    --annotations "com.gitlab.ci.user.name=$GITLAB_USER_NAME" \
    --annotations "com.gitlab.ci.pipeline.id=$CI_PIPELINE_ID" \
    # Additional annotations removed for readability
    --annotations "tag=$IMAGE_TAG"

이 단계에서는 이미지 다이제스트를 가져옵니다. 그런 다음 Cosign을 사용하여 이미지에 서명하고 여러 주석을 추가합니다.

서명 및 주석 확인#

이미지에 서명한 후에는 서명과 추가된 주석을 확인하는 것이 중요합니다.

.gitlab-ci.yml 파일에 cosign verify 명령어를 사용하는 확인 단계를 포함합니다:

- |
  cosign verify \
    --annotations "tag=$IMAGE_TAG" \
    --certificate-identity "$CI_PROJECT_URL//.gitlab-ci.yml@refs/heads/$CI_COMMIT_REF_NAME" \
    --certificate-oidc-issuer "$CI_SERVER_URL" \
    "$IMAGE_URI" | jq .

확인 단계는 이미지에 첨부된 출처 데이터가 올바르고 변조되지 않았음을 보장합니다. cosign verify 명령어는 서명을 확인하고 주석을 검사합니다. 출력에는 서명 프로세스 중 이미지에 추가한 모든 주석이 표시됩니다.

출력에서 다음을 포함한 이전에 추가된 모든 주석을 확인할 수 있습니다:

  • GitLab 사용자 이름
  • 파이프라인 ID 및 URL
  • 잡 ID 및 URL
  • 커밋 SHA 및 참조 이름
  • 프로젝트 경로
  • 이미지 소스 및 리비전

이러한 주석을 확인하면 이미지의 출처 데이터가 그대로 있고 빌드 프로세스를 기반으로 예상한 내용과 일치하는지 확인할 수 있습니다.

.gitlab-ci.yml 구성 예시#

이전 모든 단계를 따르면 .gitlab-ci.yml 파일은 다음과 같아야 합니다:

stages:
  - build

build_and_sign:
  stage: build
  image: docker:cli
  services:
    - docker:dind  # Enable Docker-in-Docker service to allow Docker commands inside the container
  variables:
    IMAGE_TAG: $CI_COMMIT_SHORT_SHA  # Use the commit short SHA as the image tag
    IMAGE_URI: $CI_REGISTRY_IMAGE:$IMAGE_TAG  # Construct the full image URI with the registry, project path, and tag
    COSIGN_YES: "true"  # Automatically confirm actions in Cosign without user interaction
    FF_SCRIPT_SECTIONS: "true"  # Enables GitLab's CI script sections for better multi-line script output
  id_tokens:
    SIGSTORE_ID_TOKEN:
      aud: sigstore  # Provide an OIDC token for keyless signing with Cosign
  before_script:
    - apk add --no-cache cosign jq  # Install Cosign (mandatory) and jq (optional)
    - docker login -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" "$CI_REGISTRY"  # Log in to the Docker registry using GitLab CI token
  script:
    # Build the Docker image using the specified tag and push it to the registry
    - docker build --pull -t "$IMAGE_URI" .
    - docker push "$IMAGE_URI"

    # Retrieve the digest of the pushed image to use in the signing step
    - IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_URI")

    # Sign the image using Cosign with annotations that provide metadata about the build and tag annotation to allow verifying
    # the tag->digest mapping (https://github.com/sigstore/cosign?tab=readme-ov-file#tag-signing)
    - |
      cosign sign "$IMAGE_DIGEST" \
        --registry-referrers-mode oci-1-1 \
        --annotations "com.gitlab.ci.user.name=$GITLAB_USER_NAME" \
        --annotations "com.gitlab.ci.pipeline.id=$CI_PIPELINE_ID" \
        --annotations "com.gitlab.ci.pipeline.url=$CI_PIPELINE_URL" \
        --annotations "com.gitlab.ci.job.id=$CI_JOB_ID" \
        --annotations "com.gitlab.ci.job.url=$CI_JOB_URL" \
        --annotations "com.gitlab.ci.commit.sha=$CI_COMMIT_SHA" \
        --annotations "com.gitlab.ci.commit.ref.name=$CI_COMMIT_REF_NAME" \
        --annotations "com.gitlab.ci.project.path=$CI_PROJECT_PATH" \
        --annotations "org.opencontainers.image.source=$CI_PROJECT_URL" \
        --annotations "org.opencontainers.image.revision=$CI_COMMIT_SHA" \
        --annotations "tag=$IMAGE_TAG"

    # Verify the image signature using Cosign to ensure it matches the expected annotations and certificate identity
    - |
      cosign verify \
        --annotations "tag=$IMAGE_TAG" \
        --certificate-identity "$CI_PROJECT_URL//.gitlab-ci.yml@refs/heads/$CI_COMMIT_REF_NAME" \
        --certificate-oidc-issuer "$CI_SERVER_URL" \
        "$IMAGE_URI" | jq .  # Use jq to format the verification output for easier readability