애플리케이션은 민감한 정보를 가상 머신(VM) 인스턴스에 전송하기 전에 Google에서 서명한 인스턴스 ID 토큰을 사용하여 인스턴스의 ID를 확인할 수 있습니다. 각 인스턴스에는 인스턴스에 대한 세부정보와 Google의 RS256 서명이 포함된 고유한 JSON 웹 토큰(JWT)이 있습니다. 애플리케이션은 Google의 공개 Oauth2 인증서와 대조해 서명을 확인하여 연결을 설정한 인스턴스의 ID를 확인합니다.
인스턴스가 인스턴스 메타데이터에 요청하는 경우에만 Compute Engine은 서명된 인스턴스 토큰을 생성합니다. 인스턴스는 자체의 고유 토큰에만 액세스할 수 있으며 다른 인스턴스의 토큰에는 액세스할 수 없습니다.
다음과 같은 시나리오에서 인스턴스의 ID를 확인해야 할 수 있습니다.
- 인스턴스를 처음 시작할 때 애플리케이션은 민감한 정보를 인스턴스에 전송하기 전에 애플리케이션에 연결된 인스턴스에 유효한 ID가 있는지 확인해야 할 수 있습니다.
- 정책에 의거하여 Compute Engine 환경 외부에 사용자 인증 정보를 저장하고 정기적으로 해당 사용자 인증 정보를 임시 사용 용도로 인스턴스에 전송하는 경우 애플리케이션은 사용자 인증 정보를 전송해야 할 때마다 인스턴스의 ID를 확인할 수 있습니다.
Google의 인스턴스 인증 방법은 다음과 같은 이점이 있습니다.
- Compute Engine은 인스턴스에서 요청할 때마다 고유한 토큰을 만들며, 각 토큰은 1시간 이내에 만료됩니다. 인스턴스의 ID 토큰을 한 번만 허용하도록 애플리케이션을 구성할 수 있으며, 이렇게 하면 승인받지 않은 시스템이 토큰을 재사용할 위험이 줄어듭니다.
- 서명된 메타데이터 토큰은 개방형 업계 표준인 RFC 7519와 ID 레이어인 OpenID Connect 1.0을 사용하므로, 기존의 도구와 라이브러리가 ID 토큰과 원활하게 작동합니다.
시작하기 전에
- 인스턴스 메타데이터 값 검색 방법을 이해합니다.
- JSON 웹 토큰의 기본사항을 이해하여 애플리케이션에서 이 토큰을 사용하는 방법을 익힙니다.
- 인스턴스에서 서비스 계정 만들기 및 사용 설정 방법을 이해합니다. 인스턴스에는 연결된 서비스 계정이 있어야 인스턴스가 ID 토큰을 검색할 수 있습니다. 서비스 계정은 IAM 권한 없이도 이러한 ID 토큰을 검색할 수 있습니다.
-
아직 인증을 설정하지 않았다면 설정합니다.
인증은 Google Cloud 서비스 및 API에 액세스하기 위해 ID를 확인하는 프로세스입니다.
로컬 개발 환경에서 코드 또는 샘플을 실행하려면 다음 옵션 중 하나를 선택하여 Compute Engine에 인증하면 됩니다.
로컬 개발 환경에서 이 페이지의 Python 샘플을 사용하려면 gcloud CLI를 설치 및 초기화한 다음 사용자 인증 정보로 애플리케이션 기본 사용자 인증 정보를 설정하세요.
- Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
If you're using a local shell, then create local authentication credentials for your user account:
gcloud auth application-default login
You don't need to do this if you're using Cloud Shell.
자세한 내용은 다음을 참조하세요: Set up authentication for a local development environment.
인스턴스 ID 확인
일부 시나리오에서 애플리케이션은 Compute Engine에서 실행 중인 인스턴스에 민감한 정보를 전송하기 전에 해당 인스턴스의 ID를 확인해야 합니다. 한 가지 일반적인 예로, Compute Engine 외부에서 실행 중인 시스템('Host1') 하나와 Compute Engine 인스턴스('VM1') 하나가 있는 경우 다음 프로세스에 따라 VM1을 Host1에 연결하고 해당 인스턴스의 ID를 검증할 수 있습니다.
원하는 보안 연결 프로토콜(예: HTTPS)을 사용하여 VM1에서 Host1으로 보안 연결을 설정합니다.
VM1이 메타데이터 서버에 고유한 ID 토큰을 요청하고 토큰의 대상을 지정합니다. 이 예시에서 대상 값은 Host1의 URI입니다. 메타데이터 서버 요청에는 이후 Host1이 토큰 검증 단계 도중에 값을 확인할 수 있도록 대상 URI가 포함됩니다.
Google에서 JWT 형식의 새 고유 인스턴스 ID 토큰을 생성하여 VM1에 제공합니다. 토큰의 페이로드에는 인스턴스에 대한 여러 세부정보와 대상 URI도 포함됩니다. 토큰 콘텐츠에 대한 전체 설명은 토큰 콘텐츠를 참조하세요.
VM1이 기존 보안 연결을 통해 Host1에 ID 토큰을 전송합니다.
Host1이 ID 토큰을 디코딩하여 토큰 헤더 및 페이로드 값을 얻습니다.
Host1이 대상 값을 확인하고 공개 Google 인증서와 대조해 인증서 서명을 확인하여 Google에서 서명한 토큰인지 검증합니다.
유효한 토큰이라면 Host1이 전송을 진행하고 전송이 완료되면 연결을 종료합니다. 이후 VM1에 연결할 때는 Host1 및 다른 시스템이 새 토큰을 요청해야 합니다.
인스턴스 ID 토큰 받기
가상 머신 인스턴스는 ID 토큰 제공 요청을 수신하면 인스턴스 메타데이터를 구하는 일반적인 프로세스를 사용하여 메타데이터 서버에 이 토큰을 요청합니다. 예를 들어 다음 중 한 가지 방법을 사용할 수 있습니다.
cURL
curl
요청을 작성하고 audience
매개변수에 값을 포함합니다.
선택사항으로 페이로드에 프로젝트 및 인스턴스 세부정보를 포함할지 여부를 지정하는 format
매개변수를 포함할 수 있습니다. full
형식을 사용하는 경우 페이로드에 라이선스 코드를 포함할지 여부를 지정하는 licenses
매개변수를 포함할 수 있습니다.
curl -H "Metadata-Flavor: Google" \ 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=AUDIENCE&format=FORMAT&licenses=LICENSES'
다음을 바꿉니다.
AUDIENCE
: 인스턴스와 이 인스턴스의 ID를 확인하는 시스템에서 모두 합의한 고유한 URI입니다. 예를 들어 이 두 시스템 사이의 연결에 사용되는 URL이 대상일 수 있습니다.FORMAT
: 페이로드에 프로젝트 및 인스턴스 세부정보를 포함할지 여부를 지정하는 선택적인 매개변수입니다. 이 정보를 페이로드에 포함하려면full
를 지정하고 포함하지 않으려면standard
를 지정합니다. 기본값은standard
입니다. 자세한 내용은 ID 토큰 형식을 참조하세요.LICENSES
: 이 인스턴스와 연관된 이미지의 라이선스 코드를 페이로드에 포함할지 여부를 지정하는 선택적인 매개변수입니다. 이 정보를 페이로드에 포함하려면TRUE
를 지정하고 포함하지 않으려면FALSE
를 지정합니다. 기본값은FALSE
입니다.format
이full
이면 영향을 주지 않습니다.
이 요청에 대해 메타데이터 서버는 RS256 알고리즘을 사용하여 서명한 JSON 웹 토큰으로 응답합니다. 이 토큰에는 Google 서명과 페이로드의 추가 정보가 포함됩니다. 이 토큰을 다른 시스템 및 애플리케이션에 전송하여 토큰 검증 및 인스턴스 ID 확인을 수행하도록 할 수 있습니다.
Python
Python requests
라이브러리의 메서드를 사용하여 인스턴스에서 메타데이터 서버로 간단한 요청을 제출할 수 있습니다. 다음 예시에서는 인스턴스 ID 토큰을 요청한 후 이를 인쇄합니다. 토큰은 이 요청을 생성하는 인스턴스에 대해 고유합니다.
이 요청에 대해 메타데이터 서버는 RS256 알고리즘을 사용하여 서명한 JSON 웹 토큰으로 응답합니다. 이 토큰에는 Google 서명과 페이로드의 추가 정보가 포함됩니다. 이 토큰을 다른 시스템 및 애플리케이션에 전송하여 토큰 검증 및 인스턴스 ID 확인을 수행하도록 할 수 있습니다.
토큰 검증
애플리케이션은 Compute Engine 인스턴스에서 인스턴스 ID 토큰을 수신한 후 다음 프로세스에 따라 이 토큰을 검증할 수 있습니다.
가상 머신 인스턴스에서 토큰을 수신하고 RS256 JWT 디코더를 사용하여 토큰을 디코딩한 다음 헤더 콘텐츠를 읽어
kid
값을 얻습니다.공개 Google 인증서와 대조해 토큰을 확인하여 토큰이 서명되었는지 확인합니다. 각 공개 인증서에는 토큰 헤더의
kid
값에 해당하는kid
값이 있습니다.토큰이 유효한 경우 페이로드 콘텐츠와 예상 값을 비교합니다. 토큰 페이로드에 인스턴스 및 프로젝트에 대한 세부정보가 있는 경우 애플리케이션이
instance_id
,project_id
,zone
값을 확인할 수 있습니다. 이러한 값은 애플리케이션이 원하는 프로젝트 내의 적절한 인스턴스와 통신하는지 확인하는, 전역적으로 고유한 튜플입니다.
토큰을 디코딩하고 검증하는 데 임의의 도구를 사용할 수 있지만, 일반적인 방법은 원하는 언어의 라이브러리를 사용하는 것입니다. 예를 들어 Python용 Google OAuth 2.0 라이브러리의 verify_token
메서드를 사용할 수 있습니다. verify_token
메서드는 kid
값을 해당 인증서에 일치시키고, 서명을 확인하고, 대상 클레임을 확인하고, 토큰에서 페이로드 콘텐츠를 반환합니다.
애플리케이션이 토큰과 토큰 콘텐츠를 검증한 후에는 보안 연결을 통해 이 인스턴스와 통신한 다음 완료 시 연결을 종료할 수 있습니다. 이후에 연결할 때는 인스턴스에서 새 토큰을 요청하고 인스턴스의 ID를 다시 확인합니다.
토큰 콘텐츠
인스턴스 ID 토큰의 3가지 주요 요소는 다음과 같습니다.
헤더
헤더에는 서명을 확인할 때 사용해야 하는 공개 Oauth2 인증서를 식별하는 kid
값이 있습니다. 서명이 RS256 알고리즘을 사용하여 생성되었음을 확인하는 alg
값도 있습니다.
{
"alg": "RS256",
"kid": "511a3e85d2452aee960ed557e2666a8c5cedd8ae",
}
페이로드
페이로드에는 aud
대상 클레임이 있습니다. 인스턴스가 토큰을 요청할 때 format=full
을 지정했다면 페이로드에는 가상 머신 인스턴스 및 해당 프로젝트에 대한 클레임도 포함됩니다.
전체 형식 토큰을 요청할 때 licenses=TRUE
를 지정하면 인스턴스와 연결된 라이선스에 대한 클레임도 포함됩니다.
{
"iss": "[TOKEN_ISSUER]",
"iat": [ISSUED_TIME],
"exp": [EXPIRED_TIME],
"aud": "[AUDIENCE]",
"sub": "[SUBJECT]",
"azp": "[AUTHORIZED_PARTY]",
"google": {
"compute_engine": {
"project_id": "[PROJECT_ID]",
"project_number": [PROJECT_NUMBER],
"zone": "[ZONE]",
"instance_id": "[INSTANCE_ID]",
"instance_name": "[INSTANCE_NAME]",
"instance_creation_timestamp": [CREATION_TIMESTAMP],
"instance_confidentiality": [INSTANCE_CONFIDENTIALITY],
"license_id": [
"[LICENSE_1]",
...
"[LICENSE_N]"
]
}
}
}
각 항목의 의미는 다음과 같습니다.
[TOKEN_ISSUER]
: 토큰 발급 주체를 식별하는 URL입니다. Compute Engine의 경우 이 값은https://accounts.google.com
입니다.[ISSUED_TIME]
: 토큰이 발급된 시간을 나타내는 unix 타임스탬프입니다. 이 값은 인스턴스가 메타데이터 서버에 토큰을 요청할 때마다 업데이트됩니다.[EXPIRED_TIME]
: 토큰이 만료되는 시간을 나타내는 unix 타임스탬프입니다.[AUDIENCE]
: 인스턴스와 이 인스턴스의 ID를 확인하는 시스템에서 모두 합의한 고유한 URI입니다. 예를 들어 이 두 시스템 사이의 연결에 사용되는 URL이 대상일 수 있습니다.[SUBJECT]
: 토큰의 제목으로, 인스턴스와 연결한 서비스 계정의 고유 ID입니다.[AUTHORIZED_PARTY]
: ID 토큰을 발급받는 주체로, 인스턴스와 연결한 서비스 계정의 고유 ID입니다.[PROJECT_ID]
: 만든 인스턴스가 속한 프로젝트의 ID입니다.[PROJECT_NUMBER]
: 만든 인스턴스가 속한 프로젝트의 고유 번호입니다.[ZONE]
: 인스턴스가 있는 영역입니다.[INSTANCE_ID]
: 이 토큰이 속한 인스턴스의 고유 ID입니다. 이 ID는 프로젝트와 영역 내에서 고유합니다.[INSTANCE_NAME]
: 이 토큰이 속한 인스턴스의 이름입니다. 프로젝트에서 영역 DNS를 사용하는 경우 이 이름은 영역 간에 재사용할 수 있으므로 고유한 인스턴스 ID를 식별하려면project_id
,zone
,instance_id
값의 조합을 사용합니다. 전역 DNS가 사용 설정된 프로젝트는 프로젝트 전체에서 고유한 인스턴스 이름을 가집니다.[CREATION_TIMESTAMP]
: 인스턴스를 만든 시간을 나타내는 Unix 타임스탬프입니다.[INSTANCE_CONFIDENTIALITY]
: 인스턴스가 컨피덴셜 VM이면1
입니다.[LICENSE_1]
~[LICENSE_N]
: 이 인스턴스와 연관된 이미지의 라이선스 코드입니다.
페이로드의 형식은 다음과 같습니다.
{
"iss": "https://accounts.google.com",
"iat": 1496953245,
"exp": 1496956845,
"aud": "https://www.example.com",
"sub": "107517467455664443765",
"azp": "107517467455664443765",
"google": {
"compute_engine": {
"project_id": "my-project",
"project_number": 739419398126,
"zone": "us-west1-a",
"instance_id": "152986662232938449",
"instance_name": "example",
"instance_creation_timestamp": 1496952205,
"instance_confidentiality": 1,
"license_id": [
"1000204"
]
}
}
}
서명
Google에서는 헤더와 페이로드를 base64url로 인코딩하고 이 두 값을 연결하여 서명을 생성합니다. 이 값을 공개 Oauth2 인증서와 대조하여 토큰을 검증할 수 있습니다.
다음 단계
- Google Cloud 아키텍처 프레임워크를 검토합니다.