고객 관리 암호화 키 (CMEK)를 사용하여 Cloud Functions 암호화

1. 소개

개요

Cloud Functions는 경량형 컴퓨팅 솔루션으로, 서버 또는 런타임 환경을 관리할 필요 없이 Cloud 이벤트에 응답하는 것이 유일한 목적인 독립 실행형 함수를 만들기 위해 사용합니다.

Cloud Key Management Service 고객 관리 암호화 키 (CMEK)를 사용하여 Cloud Functions 및 관련 저장 데이터를 보호할 수 있습니다. CMEK로 함수를 배포하면 사용자가 전적으로 제어할 수 있는 암호화 키를 사용하여 연결된 데이터를 보호할 수 있습니다. 이러한 유형의 암호화를 사용하면 금융 서비스와 같은 특정 업종에서 규정 준수 요구사항을 충족할 수 있습니다. 키는 사용자의 소유이며 Google에서 관리하지 않으므로 키가 사용 중지되거나 폐기되면 사용자를 포함한 누구도 이러한 암호화 키로 보호되는 데이터에 액세스할 수 없습니다.

Cloud Functions의 경우 CMEK는 다음을 암호화합니다.

  • 배포를 위해 업로드되고 Google에서 Cloud Storage에 저장한 함수 소스 코드로, 빌드 프로세스에 사용됩니다.
  • 함수 소스 코드에서 빌드된 컨테이너 이미지, 배포된 함수의 각 인스턴스 등 함수 빌드 프로세스의 결과
  • 내부 이벤트 전송 채널의 저장 데이터(1세대만)

암호화되는 데이터에 대한 자세한 내용은 Cloud 함수 CMEK 문서를 참조하세요.

빌드할 항목

이 Codelab에서는 CMEK를 사용하여 암호화된 Cloud 함수 (1세대 또는 2세대)를 배포하는 방법을 보여줍니다. 이 Codelab에서는 데모 목적으로 공개 Cloud 함수, 즉 인증이 필요하지 않은 함수를 사용합니다. 인증이 필요한 다른 Cloud 함수와 마찬가지로 인증된 CMEK 지원 함수를 호출할 수 있습니다.

학습할 내용

  • 기존 대칭 키링에서 CMEK 키를 만드는 방법
  • Artifact Registry 저장소를 만드는 방법
  • 1세대 및 2세대 모두에 대해 Cloud 함수에 CMEK를 구성하는 방법

2. 설정 및 요구사항

기본 요건

  • Cloud 콘솔에 로그인했습니다
  • 이전에 HTTP 트리거 Cloud 함수를 배포했습니다 (적절한 역할 및 API가 사용 설정되어 있는지 확인하기 위해).

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화853e55310c205094.png를 클릭합니다.

55efc1aaa7a4d3ad.png

Cloud Shell을 처음 시작하는 경우에는 무엇이 있는지 설명하는 중간 화면이 표시됩니다. 중간 화면이 표시되면 계속을 클릭합니다.

92662c6a846a5c.png

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

9f0e51b578fecce5.png

가상 머신에는 필요한 개발 도구가 모두 들어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저를 사용하여 수행할 수 있습니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 자신의 프로젝트 ID로 설정된 것을 확인할 수 있습니다.

  1. Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list

명령어 결과

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project

명령어 결과

[core]
project = <PROJECT_ID>

또는 다음 명령어로 설정할 수 있습니다.

gcloud config set project <PROJECT_ID>

명령어 결과

Updated property [core/project].

3. Cloud Functions용 새 키링 및 키 만들기

다음 명령어를 실행하여 Cloud KMS API가 사용 설정되어 있는지 확인합니다.

gcloud services enable cloudkms.googleapis.com

먼저 이 Codelab에서 사용되는 키링 이름, 키 이름, 리전, 기타 변수를 포함할 환경 변수를 만듭니다.

KEYRING_NAME="keyring-functions"
REGION="us-central1"
KEY_NAME="key-encrypted-function"
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER="$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')"
USER_EMAIL="$(gcloud config list account --format "value(core.account)")"

다음으로 Cloud KMS 키 및 키 버전의 루트 리소스인 키링을 만듭니다.

gcloud kms keyrings create $KEYRING_NAME --location $REGION

마지막으로, 이제 Cloud KMS 내의 새 키링에서 대칭 키를 만들 수 있습니다.

gcloud kms keys create $KEY_NAME --keyring $KEYRING_NAME --location $REGION --purpose "encryption"

4. CMEK가 사용 설정된 Docker 형식의 Artifact Registry 저장소 만들기

이 섹션에서는 Artifact Registry에 CMEK가 사용 설정된 Docker 형식의 저장소를 만듭니다. 이 키는 Cloud 함수를 배포하는 데 사용되는 키와 동일합니다.

먼저 Artifact Registry의 서비스 계정이 필요합니다. 다음 명령어를 실행하여 만들 수 있습니다.

gcloud beta services identity create --service=artifactregistry.googleapis.com --project=$PROJECT_ID

다음 명령어를 사용하여 Artifact Registry 서비스 계정에 CryptoKey 암호화/복호화 IAM 역할 (roles/cloudkms.cryptoKeyEncrypterDecrypter)을 부여하여 키에 대한 권한을 부여합니다.

gcloud kms keys add-iam-policy-binding \
  $KEY_NAME --location $REGION --keyring=$KEYRING_NAME \
  --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com \
  --role roles/cloudkms.cryptoKeyEncrypterDecrypter

그리고 Artifact Registry에 저장소를 만드는 원칙에 역할을 부여합니다. 현재 사용 중인 계정 gcloud auth list를 실행하여 현재 활성 계정을 확인할 수 있습니다.

gcloud kms keys add-iam-policy-binding \
       $KEY_NAME --location $REGION --keyring=$KEYRING_NAME \
       --member user:$USER_EMAIL \
       --role roles/cloudkms.cryptoKeyEncrypterDecrypter

이제 CMEK가 사용 설정된 Docker 형식의 저장소를 만들 수 있습니다.

참고: 리전은 CMEK 키와 동일한 리전이어야 합니다.

REPO_NAME=my-cmek-encrypted-repo 

KEY_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/keyRings/"$KEYRING_NAME"/cryptoKeys/"$KEY_NAME" 

gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --kms-key=$KEY_FULLPATH \
    --async

다음 명령어를 실행하면 새 Artifact Registry 저장소를 볼 수 있습니다.

gcloud artifacts repositories describe $REPO_NAME --location=$REGION

5. 서비스 계정에 키 (2세대)에 대한 액세스 권한 부여

이 섹션에서는 2세대 함수를 위한 서비스 계정을 만드는 방법을 설명합니다. 1세대 함수를 만드는 경우 다음 섹션으로 진행하세요.

CryptoKey 암호화/복호화 IAM 역할 (roles/cloudkms.cryptoKeyEncrypterDecrypter)을 부여하여 여러 서비스 에이전트에 키에 대한 액세스 권한을 부여해야 합니다. 이러한 서비스 에이전트는 Cloud Storage에 저장된 소스 코드에 대한 액세스 권한을 얻고, Artifact Registry의 CMEK로 보호되는 저장소에 함수 이미지를 저장하고, CMEK로 암호화된 Cloud 함수를 배포하는 데 사용됩니다.

2세대 함수 단계

  1. Cloud Run 서비스 에이전트에 키에 대한 액세스 권한을 부여합니다.
CLOUDRUN_SA=service-$PROJECT_NUMBER@serverless-robot-prod.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$CLOUDRUN_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. Eventarc 서비스 에이전트에 키에 대한 액세스 권한을 부여합니다.
EVENTARC_SA=service-$PROJECT_NUMBER@gcp-sa-eventarc.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$EVENTARC_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. Artifact Registry 서비스 에이전트에 키에 대한 액세스 권한을 부여합니다.
AR_SA=service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$AR_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. Cloud Storage 서비스 에이전트에 키에 대한 액세스 권한을 부여합니다.
STORAGE_SA=service-$PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$STORAGE_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter

다음 섹션에서는 CMEK로 암호화된 함수를 만들고 배포하는 방법을 알아봅니다.

6. 서비스 계정에 키 (1세대)에 대한 액세스 권한 부여

이 섹션에서는 1세대 함수의 서비스 계정을 만드는 방법을 설명합니다. 이전에 2세대 함수를 위한 서비스 계정을 만든 적이 있다면 다음 섹션으로 진행하세요.

CryptoKey 암호화/복호화 IAM 역할 (roles/cloudkms.cryptoKeyEncrypterDecrypter)을 부여하여 여러 서비스 에이전트에 키에 대한 액세스 권한을 부여해야 합니다. 이러한 서비스 에이전트는 Cloud Storage에 저장된 소스 코드에 대한 액세스 권한을 얻고, Artifact Registry의 CMEK로 보호되는 저장소에 함수 이미지를 저장하고, CMEK로 암호화된 Cloud 함수를 배포하는 데 사용됩니다.

1세대 함수 단계

  1. Cloud Functions 서비스 에이전트에 키에 대한 액세스 권한을 부여합니다.
FUNCTION_SA=service-$PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$FUNCTION_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. Artifact Registry 서비스 에이전트에 키에 대한 액세스 권한을 부여합니다.
AR_SA=service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$AR_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. Cloud Storage 서비스 에이전트에 키에 대한 액세스 권한을 부여합니다.
STORAGE_SA=service-$PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$STORAGE_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter

다음 섹션에서는 CMEK로 암호화된 함수를 만들고 배포하는 방법을 알아봅니다.

7. CMEK로 암호화된 함수 만들기 (2세대)

이 섹션에서는 2세대 함수를 만드는 방법을 설명합니다. 1세대 안내를 위한 다음 섹션으로 진행할 수 있습니다.

이제 CMEK가 사용 설정된 Artifact Registry 저장소가 사용 설정되고 Cloud Functions에 키에 대한 액세스 권한을 부여했으므로 CMEK 키를 사용하여 암호화된 함수를 배포할 수 있습니다.

2세대 Functions 단계:

함수의 소스 코드 만들기

이 Codelab에서는 Node.js를 사용하지만 지원되는 런타임을 모두 사용할 수 있습니다.

먼저 디렉터리를 생성하고 cd 명령어로 해당 디렉터리로 이동합니다.

mkdir ~/cmek-function-2ndgen && cd $_

그런 다음 package.json 파일을 만듭니다.

touch package.json

echo '{
  "dependencies": {
    "@google-cloud/functions-framework": "^2.1.0"
  }
}
' > package.json

다음으로 index.js 소스 파일을 만듭니다.

touch index.js

echo 'const functions = require("@google-cloud/functions-framework");

functions.http("helloWorld", (req, res) => {
 res.send(`Hello ${req.query.name || req.body.name || "World"}!`);
});' > index.js

CMEK 암호화를 사용하여 2세대 Cloud 함수 배포

참고: 아래 예는 현재 디렉터리의 소스를 사용하여 함수를 배포하는 방법을 보여줍니다. 함수의 소스 코드와 같은 디렉터리에 있는지 확인합니다.

FUNCTION_NAME=protect-me-cmek-2ndgen
ENTRY_POINT=helloWorld

REPO_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/repositories/$REPO_NAME

gcloud beta functions deploy $FUNCTION_NAME  \
--gen2 \
--region $REGION \
--kms-key $KEY_FULLPATH \
--docker-repository $REPO_FULLPATH \
--source . \
--trigger-http \
--allow-unauthenticated \
--runtime nodejs16 \
--entry-point $ENTRY_POINT

다음 명령어를 실행하면 결과 출력에서 CMEK 키를 볼 수 있습니다.

gcloud functions describe $FUNCTION_NAME –region $REGION | grep kmsKeyName

2세대 함수 테스트

curl 명령어를 사용하여 함수를 테스트할 수 있습니다.

FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --region $REGION --format='get(serviceConfig.uri)')"

curl $FUNCTION_URL

그 결과 다음과 같은 결과가 발생합니다.

Hello World!

암호화 키가 사용 설정되어 있는 한 함수가 호출자에게 성공을 반환합니다. 그러나 암호화 키가 사용 중지되면 호출자에게 오류가 발생합니다.

다음 섹션에서는 키가 비활성화된 후 함수를 호출하면 어떻게 되는지 살펴보겠습니다.

8. CMEK로 암호화된 함수 만들기 (1세대)

이 섹션에서는 1세대 함수를 만드는 방법을 설명합니다. 이전에 2세대 함수를 만든 경우 다음 섹션으로 진행하세요.

이제 CMEK가 사용 설정된 Artifact Registry 저장소가 사용 설정되고 Cloud Functions에 키에 대한 액세스 권한을 부여했으므로 CMEK 키를 사용하여 암호화된 함수를 배포할 수 있습니다.

1세대 Functions 단계:

1세대 함수의 소스 코드 만들기

이 Codelab에서는 Node.js를 사용하지만 지원되는 런타임을 모두 사용할 수 있습니다.

먼저 디렉터리를 생성하고 cd 명령어로 해당 디렉터리로 이동합니다.

mkdir ~/cmek-function-1stgen && cd $_

다음으로 package.json 파일을 만듭니다.

touch package.json

echo '{
    "name": "function-cmek-codelab",
    "version": "0.0.1"
}' > package.json

그런 다음 index.js 소스 파일을 만듭니다.

touch index.js

echo "exports.helloWorld = (req, res) => {
    let message = req.query.message || req.body.message || 'Hello World!';
    res.status(200).send(message);
};" > index.js

CMEK 암호화를 사용하여 1세대 Cloud 함수 배포

참고: 아래 예는 현재 디렉터리의 소스를 사용하여 함수를 배포하는 방법을 보여줍니다. 함수의 소스 코드와 같은 디렉터리에 있는지 확인합니다.

FUNCTION_NAME=protect-me-cmek-1stgen
ENTRY_POINT=helloWorld

REPO_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/repositories/$REPO_NAME

gcloud functions deploy $FUNCTION_NAME  \
--region $REGION \
--kms-key $KEY_FULLPATH \
--docker-repository $REPO_FULLPATH \
--source . \
--trigger-http \
--allow-unauthenticated \
--runtime nodejs16 \
--entry-point $ENTRY_POINT

다음 명령어를 실행하면 결과 출력에서 CMEK 키를 볼 수 있습니다.

gcloud functions describe $FUNCTION_NAME –region $REGION | grep kmsKeyName

1세대 함수 테스트

curl 명령어를 사용하여 함수를 테스트할 수 있습니다.

FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --region $REGION --format='get(httpsTrigger.url)')"

curl $FUNCTION_URL

그 결과 다음과 같은 결과가 발생합니다.

Hello World!

암호화 키가 사용 설정되어 있는 한 함수가 호출자에게 성공을 반환합니다. 그러나 암호화 키가 사용 중지되면 호출자에게 오류가 발생합니다.

다음 섹션에서는 키가 비활성화된 후 함수를 호출하면 어떻게 되는지 알아보겠습니다.

9. 암호화 키가 사용 중지된 CMEK 암호화 함수 호출

이 마지막 섹션에서는 키를 무효화하고 함수를 다시 호출하여 결과 오류를 확인합니다.

암호화 키 사용 중지

다음 명령어를 실행하여 키를 사용 중지할 수 있습니다. 이 Codelab에서는 하나의 키 버전만 생성하므로 버전 1을 사용 중지합니다.

gcloud kms keys versions disable 1 \
    --key=$KEY_NAME \
    --keyring=$KEYRING_NAME \
    --location=$REGION

결과 정보가 표시됩니다.

algorithm: GOOGLE_SYMMETRIC_ENCRYPTION
createTime: '2023-04-11T03:30:49.111832653Z'
generateTime: '2023-04-11T03:30:49.111832653Z'
name: projects/dogfood-gcf-saraford/locations/us-central1/keyRings/myKeyRing/cryptoKeys/encrypted-function/cryptoKeyVersions/1
protectionLevel: SOFTWARE
state: DISABLED

사용 중지된 키로 함수 호출

이제 함수를 다시 curl합니다.

curl $FUNCTION_URL

이번에는 Hello World 응답을 받지 않게 됩니다.

Cloud 함수의 로그에 표시되는 항목:

User's CMEK key has been disabled. CMEK key: projects/<PROJECT-NAME>/locations/us-central1/keyRings/myKeyRing/cryptoKeys/encrypted-function

CMEK 키가 사용 중지된 경우 리소스 보기 시도

이 섹션에서는 CMEK 키를 사용 중지하면 다음 리소스를 사용할 수 없게 됩니다.

  • 함수 소스 코드
  • 소스 코드에서 컨테이너 이미지 빌드

예를 들어 Cloud 함수의 소스 탭을 방문하면 보관 파일을 가져오는 중에 오류가 표시됩니다. 소스 코드가 포함된 .zip 파일을 Cloud Storage에서 직접 보려고 하면 비슷한 오류가 발생합니다.

ac3307bb05d30e19.png

또한 Artifact Registry에서 함수에 컨테이너 이미지를 사용할 수 있는 액세스 권한도 없습니다. 예를 들어 해당 컨테이너 이미지를 Cloud Run에 배포하려고 하면 이미지를 찾을 수 없다는 오류가 표시됩니다.

암호화된 리소스의 전체 목록은 CMEK 함수 문서를 참조하세요.

10. 축하합니다

축하합니다. Codelab을 완료했습니다.

학습한 내용

  • 기존 대칭 키링에서 CMEK 키를 만드는 방법
  • Artifact Registry 저장소를 만드는 방법
  • Cloud 함수에 CMEK를 구성하는 방법

추가 정보

Cloud Functions 및 CMEK에 대한 자세한 내용은 다음 링크를 참조하세요.