API 키 관리 및 보안

1. 소개

이전에는 다른 방법을 사용할 수 없거나 불편하다고 여겨질 때 Google API 키를 사용하여 Google API에 액세스했습니다. 일반적인 사용 사례는 Google 지도 API 및 Firebase에서 노출하는 Google API에 대한 액세스였습니다. AI 모델, Gemini와 같은 AI 에이전트, AI Studio 및 Agent Development Kit과 같은 에이전트 개발 프레임워크가 도입되면서 API 키는 Google의 대규모 언어 모델에 액세스하는 기본 방법이 되었습니다.

API 키는 낮은 수준의 보호를 제공합니다. Google Cloud는 키의 오용을 방지하는 여러 방법을 제공하지만 활성 API 키를 보유하면 추가 인증 또는 승인 검증 없이 Google API에 액세스할 수 있습니다. API 키 사용을 제한하는 방법은 문서에 설명되어 있습니다. Cloud 블로그의 Gemini 및 Google API 키 보호 게시물에서는 API 키 유지보수에 관한 추가 권장사항을 제공합니다. 이 Codelab에서는 이러한 권장사항을 실제로 적용해 봅니다.

실습할 내용

  • Google Cloud에서 새 API 키를 만들 때 적용되는 제한사항 검토
  • 모든 API 키를 카탈로그화하고 보안 보호가 없는 키 찾기
  • 사용량에 따라 기존 API 키에 제한사항 적용
  • 비정상적인 사용이 발생할 경우 키를 삭제하는 자동화 정의

필요한 항목

  • 최신 웹브라우저 (예: Chrome)
  • Google 계정

2. 설정

이 Codelab의 안내에서는 Google Cloud 콘솔의 Cloud Shell에서 명령어를 실행한다고 가정합니다. 로컬 환경에 gcloud CLI가 있는 경우 여기에서 명령어를 실행할 수 있습니다.

단계의 작업은 Cloud 콘솔 UI를 사용하여 수행할 수 있지만 방법은 다릅니다. 이 Codelab에서는 명령줄 인터페이스를 사용하여 상호작용을 간소화하고 최신 AI 에이전트 (예: Antigravity CLI)와의 통합을 더 쉽게 사용 설정합니다.

Cloud Shell 터미널 시작

  1. 새 브라우저 창에서 https://console.cloud.google.com/ 을 사용하여 Google Cloud 콘솔을 엽니다. 최상의 사용자 환경을 위해서는 Chrome을 사용하는 것이 좋습니다.
  2. Google Cloud에서 Google 계정에 로그인합니다.
  3. Google Cloud 콘솔 상단에서 Cloud Shell 활성화 Cloud Shell 활성화 아이콘를 클릭합니다.
    표시되면 다음 창을 클릭합니다.
    • Cloud Shell 정보 창을 통해 계속 진행합니다.
    • 사용자 인증 정보를 사용하여 Google Cloud API를 호출할 수 있도록 Cloud Shell을 승인합니다.

Google Cloud 프로젝트 선택

Cloud 콘솔을 열면 인증되고 일반적으로 작업에 사용할 프로젝트 선택이 표시됩니다. 프로젝트 ID는 소문자, 숫자, 대시 기호로 구성된 6~30자의 시퀀스입니다(예: qwiklabs-gcp-04-3075fc9fd77f). Cloud Shell 터미널은 선택한 프로젝트로 gcloud CLI를 구성합니다. 다음과 비슷한 출력이 표시됩니다.

Your Cloud Platform project in this session is set to qwiklabs-gcp-04-3075fc9fd77f

이는 gcloud에 대한 추가 명령어에서 프로젝트 ID qwiklabs-gcp-04-3075fc9fd77f를 사용한다는 의미입니다.

프로젝트 ID를 환경 변수 PROJECT_ID로 설정합니다. 다음 명령어를 사용하여 모든 프로젝트의 목록을 확인할 수 있습니다.

gcloud projects list
  • gcloud에 구성된 프로젝트와 다른 프로젝트 ID를 사용하려면 your-project-id를 바꾸고 명령어를 실행합니다.
    export PROJECT_ID="your-project-id"
    
    예를 들면 다음과 같습니다.
    export PROJECT_ID="qwiklabs-gcp-04-3075fc9fd77f"
    
  • 선택한 프로젝트 ID를 사용하려면 다음 명령어를 실행합니다.
    export PROJECT_ID=$(gcloud config get project)
    

3. 새 API 키 제한

이전에는 사용자가 완전히 제한되지 않은 API 키를 만들 수 있었습니다. 제한되지 않은 키는 키가 생성된 프로젝트에서 사용 설정된 모든 Google API를 호출하는 데 사용할 수 있습니다. Google Cloud 콘솔에서는 사용자가 제한되지 않은 키를 만들 수 없지만 gcloud CLI 또는 직접 API 호출을 사용하여 만들 수 있습니다.

다음 단계에서는 사용을 특정 API 및 지정된 웹사이트로 제한하는 제한된 API 키를 만드는 방법을 보여줍니다.

  1. Google 지도 위치정보 API에서만 사용할 수 있도록 제한된 새 API 키를 만들려면 셸 터미널에서 다음 명령어를 실행합니다.
    gcloud services api-keys create --key-id=restricted-api-key \
      --display-name="restricted api key" \
      --api-target=service=geolocation.googleapis.com \
      --project=${PROJECT_ID}
    
    이 명령어는 Google 지도 위치정보 서비스를 호출하는 데 사용할 수 있는 새 API 키를 만듭니다.
  2. 애플리케이션 제한을 추가하여 키 보안을 강화합니다. 웹사이트 example.com 내의 모든 경로에서만 키 사용을 제한합니다. 다음 명령어를 실행하여 키에 애플리케이션 제한을 추가합니다.
    gcloud services api-keys update restricted-api-key \
      --location=global \
      --allowed-referrers="example.com/*" \
      --project=${PROJECT_ID}
    
    키를 특정 웹사이트에서만 사용할 수 있도록 허용하는 대신 --allowed-application을 사용하여 허용된 Android 애플리케이션 또는allowed-ips를 사용하여 허용된 IP 주소를 정의할 수 있습니다. 모든 옵션에 관한 전체 문서를 참고하세요.

정리

사용할 계획이 없다면 만든 API 키를 삭제합니다.

gcloud services api-keys delete --key-id=restricted-api-key \
  --project=${PROJECT_ID}

4. API 키 카탈로그화

이 단계에서는 gcloud CLI를 사용하여 API 키의 인벤토리를 가져옵니다. 결과 목록에는 액세스 권한이 있는 모든 활성 (삭제되지 않은) API 키가 표시됩니다.

  1. 다음 명령어를 실행하여 모든 키 이름, ID, 생성 날짜를 확인합니다.
    gcloud services api-keys list --project=${PROJECT_ID} \
      --format='value(displayName,name.basename(),createTime.date())'
    
    출력에는 사람이 읽을 수 있는 키 이름, 키 ID, 키가 생성된 날짜가 표시됩니다. 다음과 유사합니다.
    api key 1	api-key-1	2024-05-10T07:53:24
    api key 2	api-key-2	2025-06-12T14:47:57
    
  2. 키 ID 중 하나를 선택하고 다음 명령어를 붙여넣어 키에 제한사항이 있는지 확인합니다. your-key-id를 선택한 키 ID의 값으로 바꿉니다.
    gcloud services api-keys describe "your-key-id" --project=${PROJECT_ID}
    

출력 (YAML)에는 restrictions 아래에 제한사항 목록이 포함됩니다.

createTime: '2024-05-10T07:53:24.986528Z'
displayName: api key 1
etag: W/"u1WuY41K2tPKUZd7cfLoKg=="
name: projects/123456789012/locations/global/keys/api-key-1
restrictions:
  apiTargets:
  - service: geolocation.googleapis.com
  browserKeyRestrictions:
    allowedReferrers:
    - https://example.com/*
uid: 1a2b3c4d-1234-abcd-1234-a1b2c3d4e5f6
updateTime: '2024-05-10T07:53:24.071228Z'

키가 업데이트되지 않은 경우 createTimeupdateTime 필드에 동일한 타임스탬프가 표시됩니다.

  1. 모든 프로젝트를 살펴보고 제한사항이 없는 모든 API 키를 출력하는 스크립트를 다운로드하고 실행합니다.
    curl -fsSL -o unrestricted_api_keys.sh \
      "https://github.com/GoogleCloudPlatform/devrel-demos/blob/main/security/api-key-audit/unrestricted_api_keys.sh"
    chmod +x unrestricted_api_keys.sh
    ./unrestricted_api_keys.sh
    
    스크립트를 실행하면 다음과 같은 형식으로 출력이 표시됩니다.
    DISPLAY NAME    KEY ID    PROJECT ID    CREATION DATE
    Key 1    1a2b3c4d-1234-abcd-1234-a1b2c3d4e5f6    my-project-1    2024-05-10T07:53:24.071228Z
    
    이 Codelab에서 사용된 모든 스크립트는 GitHub의 devrel-demos 저장소에 있는 Security 폴더에서 확인할 수 있습니다.

5. API 키 사용량 검색

이 단계에서는 API 키를 사용하여 호출된 API를 찾는 데 도움이 되는 Google Cloud 측정항목을 쿼리합니다. 이 정보를 사용하여 키의 현재 사용량을 검토하고 추측하는 대신 실제 정보를 기반으로 키에 API 제한사항을 적용할 수 있습니다.

  1. 이전 단계에서 사용한 키 ID를 사용하거나 다른 키 ID를 선택합니다. 다음 명령어에서 your-key-id를 선택한 키 ID로 바꿉니다.
    export KEY_UID=$(
       gcloud services api-keys describe "your-key-id" \
       --format='value(uid)' \
       --project=${PROJECT_ID})
    
  2. 1년 사용 기록을 되돌아보도록 검색을 설정합니다. 더 길거나 짧은 기간을 찾으려면 365 (일 수)를 다른 양수로 바꿉니다.
    export DAYS=365
    
  3. 애플리케이션 기본 사용자 인증 정보 (ADC)를 새로고침하여 Cloud Monitoring API에 직접 호출할 수 있도록 합니다. 다음 명령어를 실행하고 터미널의 안내를 따릅니다.
    gcloud auth application-default login
    
  4. 다음 명령어를 실행하여 서비스 사용량 측정항목 데이터 요청을 Cloud Monitoring API로 보냅니다.
curl -s -G -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  --data-urlencode "filter=metric.type=\"serviceruntime.googleapis.com/api/request_count\" AND resource.labels.credential_id=\"apikey:${KEY_UID}\"" \
  --data-urlencode "interval.startTime=$(date -u -d "${DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ)" \
  --data-urlencode "interval.endTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  "https://monitoring.googleapis.com/v3/projects/${PROJECT_ID}/timeSeries" \
  | jq -r '.timeSeries[]?.resource.labels.service' | sort -u

이 명령어는 선택한 API 키 고유 ID와 일치하는 credential_id 라벨이 있는 데이터 포인트에 대해 serviceruntime/api/request_count 기본 제공 측정항목을 쿼리합니다. 그런 다음 service 라벨의 값을 가져오고 반복을 삭제하면서 값을 출력합니다.

API 키 강화

이 단계에서는 이전 단계에서 수집한 정보를 사용하여 사용량 정보를 기반으로 API 키의 제한 구성을 업데이트합니다.

이전 단계에서 사용된 동일한 API 키를 사용합니다. 필요한 경우 이전 단계의 안내를 다시 실행하여 환경 변수 PROJECT_ID, KEY_UID, DAYS가 설정되었는지 확인합니다.

  1. 다음 명령어를 실행하여 API 키를 사용하여 호출된 Google API 목록을 가져옵니다.

SERVICES=$(curl -s -G -H "Authorization: Bearer $(gcloud auth application-default print-access-token)"
–data-urlencode "filter=metric.type="serviceruntime.googleapis.com/api/request_count" AND resource.labels.credential_id="apikey:${KEY_UID}""
–data-urlencode "interval.startTime=$(date -u -d "${DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ)"
–data-urlencode "interval.endTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
"https://monitoring.googleapis.com/v3/projects/${PROJECT_ID}/timeSeries"
| jq -r ‘.timeSeries[]?.resource.labels.service' | sort -u)

1. Build the list of arguments to restrict the API usage for the API key based
on the retrieved list.

```shell
API_TARGET_ARGS=()
for SERVICE in $SERVICES; do
  API_TARGET_ARGS+=("--api-target=service=${SERVICE}")
done
  1. 비어 있지 않은 목록의 제한된 API 목록을 바꿉니다.
    if [ ${#API_TARGET_ARGS[@]} -gt 0 ]; then
        gcloud services api-keys update "projects/${PROJECT_ID}/locations/global/keys/${KEY_UID}" \
        ${API_TARGET_ARGS}
    fi
    

6. 이상치 사용 감지 정의

이전 단계에서는 API 키를 탐색하고 강화하는 방법을 보여주었습니다. 이 단계에서는 Monitoring 알림을 사용하여 키 사용량의 예기치 않은 급증에 대한 응답을 자동화하는 방법을 보여줍니다.

다음 안내에서는 API 키를 사용하는 API 호출 비율이 지난 5분 동안 10% 이상 증가할 때 실행되는 알림을 만듭니다. 알림은 추가 사용을 방지하기 위해 API 키를 삭제하는 Cloud Build 스크립트를 트리거하도록 구성됩니다. 키는 향후 30일 이내에 복원할 수 있습니다. 키를 삭제 취소하는 방법을 알아보려면 문서를 참고하세요.

이 안내에서는 이전 단계에서 사용한 변수 PROJECT_IDKEY_UID를 재사용합니다. 다른 키 또는 프로젝트를 선택하려면 설정 및 API 키 사용량 검색 단계에 설명된 대로 이러한 변수의 새 값을 설정합니다.

  1. 다음 스크립트를 실행하여 알림 정책 파일을 만듭니다.
    cat <<EOF > alert_policy.json
    {
      "displayName": "Credential API Request Count Increase Alert (Project: ${PROJECT_ID})",
      "combiner": "OR",
      "conditions": [
        {
          "displayName": "API Request Count Increase > 10% in 5m with Min Volume",
          "conditionPrometheusQueryLanguage": {
            "query": "(sum(increase(serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\\"apikey:${KEY_UID}\\"}[5m])) / (sum(increase(serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\\"apikey:${KEY_UID}\\"}[5m] offset 5m)) or on() vector(1)) > 1.10) and (sum(increase(serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\\"apikey:${KEY_UID}\\"}[5m])) > 50)",
            "duration": "0s",
            "evaluationInterval": "60s"
          }
        }
      ],
      "enabled": true
    }
    EOF
    
    알림 정책은 다음 PromQL 필터를 사용하여 알림을 트리거합니다.
     (sum(
       increase(
         serviceruntime_googleapis_com:api_request_count{metric_label_credential_id="API_KEY_UID"}[5m])
     ) /
     (sum(
       increase(
         serviceruntime_googleapis_com:api_request_count{metric_label_credential_id="API_KEY_UID"}[5m] offset 5m)
     ) or on() vector(1)) > 1.10)
    and
     (sum(
       increase(
         serviceruntime_googleapis_com:api_request_count{metric_label_credential_id=\"YOUR_CREDENTIAL_ID_HERE\"}[5m])) > 50)
    
    증가율을 계산하고 이전 창과 비교합니다. 10% 보다 클 때만 알림을 트리거합니다. 총 호출 수가 무시할 수 있는 경우 알림이 트리거되지 않도록 창에서 50개 이상의 API 호출이 트리거되도록 조건을 지정합니다. 이전 5분 비율이 0일 때 NaN (0으로 삭제) 계산을 방지하기 위해 이전 창 비율이 0이면 분모를 1로 대체합니다.창 길이 (5m), 최소 임곗값 (50), 10% 증가 임곗값 (1.10)과 같은 알림 매개변수를 변경할 수 있습니다.추가 정책 매개변수는 조건이 충족되면 알림이 실행되어야 하고 (duration) 60초마다 조건을 프로브해야 한다고 (evaluationInterval) 정의합니다.
  2. 다음 명령어를 실행하여 알림 알림을 게시하는 데 사용되는 PubSub 주제를 만듭니다.
    gcloud pubsub topics create api-key-alert-notifications --project=$PROJECT_ID
    
  3. 다음 명령어를 실행하여 PubSub를 사용하는 알림의 알림 채널을 만듭니다.
    CHANNEL_NAME=$(gcloud beta monitoring channels create \
      --display-name="Pub/Sub Alert Channel" \
      --type="pubsub" \
      --channel-labels="topic=projects/$PROJECT_ID/topics/api-key-alert-notifications" \
      --format='value(name)' \
      --project=$PROJECT_ID)
    
    삭제 단계에서 CHANNEL_NAME 환경 변수를 사용합니다.
  4. 다음 명령어를 실행하여 새 모니터링 알림을 만듭니다.
    gcloud monitoring policies create --policy-from-file=alert_policy.json \
      --project=$PROJECT_ID
    
  5. 다음 명령어를 실행하여 Cloud Build 서비스 권한을 부여하여 프로젝트에서 API 키를 삭제합니다.
    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
      --role="roles/apikeys.admin"
    
    apikeys.admin 역할을 제한하여 API 키의 특정 인스턴스만 조작할 수 있습니다. 자세한 내용은 IAM 조건을 참고하세요.
  6. 다음 스크립트를 실행하여 API 키를 삭제하는 Cloud Build 트리거를 만듭니다.
    cat <<EOF > trigger_config.yaml
    name: "delete-compromised-api-key"
    description: "Triggered by Pub/Sub alert to automatically delete the leaking API Key"
    pubsubConfig:
      topic: "projects/${PROJECT_ID}/topics/api-key-alert-notifications"
    build:
      steps:
      - name: "gcr.io/google.com/cloudsdktool/cloud-sdk:slim"
        args:
        - "gcloud"
        - "services"
        - "api-keys"
        - "delete"
        - "${KEY_UID}"
        - "--quiet"
    EOF
    
  7. 다음 명령어를 실행하여 새 모니터링 알림 트리거를 만듭니다.
    gcloud builds triggers create pubsub \
      --trigger-config=trigger_config.yaml \
      --project=$PROJECT_ID
    

이제 알림 정책 및 Cloud Build 트리거 구성 파일을 삭제할 수 있습니다.

rm alert_policy.json trigger_config.yaml

또는 Terraform 계획을 사용하여 이 자동화를 설정할 수 있습니다. Google Cloud DevRel 저장소abnormal-usage-detection 폴더에서 Terraform 파일을 다운로드합니다. 이 계획은 프로젝트 ID와 API 키 UID를 입력 매개변수로 허용하고 이 단계에서 본 리소스와 구성을 설정합니다.

7. 정리

Google Cloud 계정에 예기치 않은 요금이 청구되지 않도록 하려면 이 실습 중에 만든 Pub/Sub 주제, Cloud Build 트리거, 알림 정책을 삭제해야 합니다.

다음 명령어를 실행하여 만든 모든 리소스를 삭제합니다.

gcloud builds triggers delete delete-compromised-api-key \
  --project=$PROJECT_ID
gcloud beta monitoring channels delete $CHANNEL_NAME \
  --project=$PROJECT_ID \
  --quiet
gcloud pubsub topics delete api-key-alert-notifications \
  --project=$PROJECT_ID
gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
  --role="roles/apikeys.admin"

8. 요약

이 Codelab에서는 Google Cloud API 키를 위한 강력한 엔드 투 엔드 보안 및 자동화 프레임워크를 구현했습니다.

  1. 강화된 기본 구성: API 키를 만들고 제한하여 필요한 API 및 신뢰할 수 있는 플랫폼 (예: 특정 HTTP 리퍼러)에만 액세스를 제한했습니다.
  2. 키 인벤토리 감사: 프로젝트 환경을 검사하여 즉각적인 보안 위험을 나타내는 제한되지 않은 키를 감지하고 격리했습니다.
  3. 사용량 데이터 분석: 프로그래매틱 방식으로 Cloud Monitoring 측정항목 데이터를 쿼리하여 이전 키 사용률을 프로파일링하여 확인된 사용량 발자국을 기반으로 키를 제한할 수 있습니다.
  4. 자동화된 위협 완화: Cloud Monitoring 알림 정책을 Pub/Sub 주제 및 Cloud Build 트리거에 연결하여 반응형 '회로 차단기'를 설정하여 비정상적인 트래픽 급증 중에 손상된 키를 자동으로 삭제할 수 있습니다.

다음 단계

  • 모든 API 키에 제한사항 적용: 이 실습에서 배운 내용을 사용하여 부분적으로 제한되거나 제한되지 않은 모든 API 키를 감지하고 API 및 클라이언트 제한사항을 적용합니다.
  • API 키에 '회로 차단기' 설정: 갑작스러운 소비 증가 시 자동 키 삭제를 설정하여 예기치 않은 사용으로부터 API 키를 추가로 보호합니다. 실습에 표시된 gcloud 명령어 또는 Terraform을 사용합니다. IAM 조건을 활용하여 권한을 강화하는 것이 좋습니다.
  • Monitoring 알림 살펴보기: Google Cloud Monitoring 서비스를 사용하여 알림을 설정하는 방법을 자세히 알아봅니다.
  • Google Cloud에서 사용할 수 있는 액세스 제어 자세히 알아보기: 액세스 경계 정책액세스 변경 전파를 검토합니다.