시작하기 전에
제약조건 프레임워크
gcloud beta terraform vet
는 제약조건과 제약조건 템플릿으로 구성된 제약조건 프레임워크 정책을 사용합니다. 두 구성요소의 차이점은 다음과 같습니다.
- 제약조건 템플릿은 함수 선언과 유사합니다. Rego에서 규칙을 정의하고 선택적으로 입력 매개변수를 사용합니다.
- 제약조건은 제약조건 템플릿을 참조하고 전달할 입력 매개변수와 정책이 적용되는 리소스를 정의하는 파일입니다.
이렇게 하면 반복을 방지할 수 있습니다. 일반 정책으로 제약조건 템플릿을 작성한 후 다른 입력 매개변수나 다른 리소스 일치 규칙을 제공하는 제약조건을 임의의 수만큼 작성할 수 있습니다.
제약조건 템플릿 만들기
제약조건 템플릿을 만들려면 다음 단계를 수행합니다.
- 샘플 데이터 수집
- Rego 쓰기
- Rego 테스트
- 제약조건 템플릿 스켈레톤 설정
- Rego 인라인 처리
- 제약조건 설정
샘플 데이터 수집
제약조건 템플릿을 작성하려면 작동할 샘플 데이터가 있어야 합니다. Terraform 기반 제약조건은 Terraform 계획 JSON의 resource_changes
키에서 제공되는 리소스 변경 데이터에서 작동합니다.
예를 들어 JSON은 다음과 비슷합니다.
// tfplan.json
{
"format_version": "0.2",
"terraform_version": "1.0.10",
"resource_changes": [
{
"address": "google_compute_address.internal_with_subnet_and_address",
"mode": "managed",
"type": "google_compute_address",
"name": "internal_with_subnet_and_address",
"provider_name": "registry.terraform.io/hashicorp/google",
"change": {
"actions": [
"create"
],
"before": null,
"after": {
"address": "10.0.42.42",
"address_type": "INTERNAL",
"description": null,
"name": "my-internal-address",
"network": null,
"prefix_length": null,
"region": "us-central1",
"timeouts": null
},
"after_unknown": {
"creation_timestamp": true,
"id": true,
"network_tier": true,
"project": true,
"purpose": true,
"self_link": true,
"subnetwork": true,
"users": true
},
"before_sensitive": false,
"after_sensitive": {
"users": []
}
}
}
],
// other data
}
Rego 쓰기
샘플 데이터가 준비되면 Rego에서 제약조건 템플릿 로직을 작성할 수 있습니다.
Rego에는 violations
규칙이 있어야 합니다. 검토 중인 리소스 변경사항은 input.review
로 제공됩니다. 제약조건 매개변수는 input.parameters
로 제공됩니다. 예를 들어 google_compute_address
리소스에 허용된 address_type
이 포함되도록 하려면 다음을 작성합니다.
# validator/tf_compute_address_address_type_allowlist_constraint_v1.rego
package templates.gcp.TFComputeAddressAddressTypeAllowlistConstraintV1
violation[{
"msg": message,
"details": metadata,
}] {
resource := input.review
resource.type == "google_compute_address"
allowed_address_types := input.parameters.allowed_address_types
count({resource.after.address_type} & allowed_address_types) >= 1
message := sprintf(
"Compute address %s has a disallowed address_type: %s",
[resource.address, resource.after.address_type]
)
metadata := {"resource": resource.name}
}
제약조건 템플릿 이름 지정
이전 예시에서는 TFComputeAddressAddressTypeAllowlistConstraintV1
이름을 사용합니다. 이는 각 제약조건 템플릿의 고유 식별자입니다. 다음과 같은 이름 지정 가이드라인을 따르는 것이 좋습니다.
- 일반 형식은
TF{resource}{feature}Constraint{version}
입니다. CamelCase를 사용합니다. 즉, 각각의 새 단어를 대문자로 바꿉니다. - 단일 리소스 제약조건의 경우 Terraform 제공업체의 제품 이름 지정 규칙을 따릅니다. 예를 들어
google_tags_tag
의 경우 제품 이름은tags
이지만 API 이름은resourcemanager
입니다. - 템플릿이 리소스 유형 2개 이상에 적용되는 경우 리소스 부분을 생략하고 특성만 포함합니다(예: 'TFAddressTypeAllowlistConstraintV1').
- 버전 번호는 semver 양식을 따르지 않습니다. 단일 숫자일 뿐입니다. 이렇게 하면 효과적으로 템플릿의 모든 버전을 고유한 템플릿으로 만들 수 있습니다.
제약조건 템플릿 이름과 일치하지만 snake_case를 사용하는 Rego 파일의 이름을 사용하는 것이 좋습니다. 즉, _
로 구분되는 이름을 소문자 단어로 변환합니다. 이전 예시에서 권장 파일 이름은 tf_compute_address_address_type_allowlist_constraint_v1.rego
입니다.
Rego 테스트
Rego Playground를 사용하여Rego를 수동으로 테스트할 수 있습니다. 민감하지 않은 정보를 사용해야 합니다.
자동 테스트를 작성하는 것이 좋습니다.
수집된 샘플 데이터를 validator/test/fixtures/<constraint
filename>/resource_changes/data.json
에 넣고 테스트 파일에서 다음과 같이 참조합니다.
# validator/tf_compute_address_address_type_allowlist_constraint_v1_test.rego
package templates.gcp.TFComputeAddressAddressTypeAllowlistConstraintV1
import data.test.fixtures.tf_compute_address_address_type_allowlist_constraint_v1_test.resource_changes as resource_changes
test_violation_with_disallowed_address_type {
parameters := {
"allowed_address_types": "EXTERNAL"
}
violations := violation with input.review as resource_changes[_]
with input.parameters as parameters
count(violations) == 1
}
Rego와 테스트를 정책 라이브러리의 validator
폴더에 배치합니다.
제약조건 템플릿 스켈레톤 설정
Rego 규칙을 작업하고 테스트했으면 제약조건 템플릿으로 패키징해야 합니다. 제약조건 프레임워크는 Kubernetes 커스텀 리소스 정의를 Rego 정책의 컨테이너로 사용합니다.
또한 제약조건 템플릿은 OpenAPI V3 스키마를 사용하여 제약조건의 입력으로 허용되는 매개변수를 정의합니다.
Rego에 사용한 이름과 동일한 이름을 스켈레톤에 사용합니다. 특히 다음 내용이 해당됩니다.
- Rego와 동일한 파일 이름을 사용합니다. 예를 들면 다음과 같습니다.
tf_compute_address_address_type_allowlist_constraint_v1.yaml
spec.crd.spec.names.kind
에는 템플릿 이름이 포함되어야 합니다.metadata.name
에는 템플릿 이름이 소문자로 포함되어야 합니다.
제약조건 템플릿 스켈레톤을 policies/templates
에 배치합니다.
위 예시의 경우 다음과 같습니다.
# policies/templates/tf_compute_address_address_type_allowlist_constraint_v1.yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: tfcomputeaddressaddresstypeallowlistconstraintv1
spec:
crd:
spec:
names:
kind: TFComputeAddressAddressTypeAllowlistConstraintV1
validation:
openAPIV3Schema:
properties:
allowed_address_types:
description: "A list of address_types allowed, for example: ['INTERNAL']"
type: array
items:
type: string
targets:
- target: validation.resourcechange.terraform.cloud.google.com
rego: |
#INLINE("validator/tf_compute_address_address_type_allowlist_constraint_v1.rego")
#ENDINLINE
Rego 인라인 처리
이 시점에서 이전 예시에 따르면 디렉터리 레이아웃은 다음과 같습니다.
| policy-library/
|- validator/
||- tf_compute_address_address_type_allowlist_constraint_v1.rego
||- tf_compute_address_address_type_allowlist_constraint_v1_test.rego
|- policies
||- templates
|||- tf_compute_address_address_type_allowlist_constraint_v1.yaml
Google 제공 정책 라이브러리 저장소를 클론한 경우 make build
를 실행하여 policies/templates
의 제약조건 템플릿을 validator
에서 정의된 Rego와 함께 자동으로 업데이트할 수 있습니다.
제약조건 설정
제약조건에는 gcloud beta terraform vet
이 위반사항을 올바르게 시행하고 보고하는 데 필요한 세 가지 정보가 포함됩니다.
severity
:low
,medium
또는high
match
: 제약조건이 특정 리소스에 적용되는지 결정하기 위한 매개변수입니다. 지원되는 일치 매개변수는 다음과 같습니다.addresses
: glob 스타일 일치를 사용하여 포함할 리소스 주소 목록excludedAddresses
: (선택사항) glob 스타일 일치를 사용하여 제외할 리소스 주소 목록
parameters
: 제약조건 템플릿의 입력 매개변수 값
kind
에 제약조건 템플릿 이름이 있는지 확인합니다. metadata.name
을 설명이 포함된 슬러그로 설정하는 것이 좋습니다.
예를 들어 이전 예시 제약조건 템플릿을 사용하여 INTERNAL
주소 유형만 허용하려면 다음을 작성합니다.
# policies/constraints/tf_compute_address_internal_only.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: TFComputeAddressAddressTypeAllowlistConstraintV1
metadata:
name: tf_compute_address_internal_only
spec:
severity: high
match:
addresses:
- "**"
parameters:
allowed_address_types:
- "INTERNAL"
일치 예시는 다음과 같습니다.
주소 일치자 | 설명 |
---|---|
`module.**` | 모든 모듈의 모든 리소스 |
`module.my_module.**` | `my_module` 모듈의 모든 항목 |
`**.google_compute_global_forwarding_rule.*` | 모든 모듈의 모든 google_compute_global_forwarding_rule 리소스 |
`module.my_module.google_compute_global_forwarding_rule.*` | `my_module`의 모든 google_compute_global_forwarding_rule 리소스 |
리소스 주소가 addresses
및 excludedAddresses
의 값과 일치하면 제외됩니다.
제한사항
Terraform 계획 데이터는 적용 후 실제 상태를 가장 잘 표현합니다. 그러나 대부분의 경우 적용 후 상태는 서버 측에서 계산되므로 이를 알 수 없습니다.
CAI 상위 경로 빌드는 정책 유효성 검사 프로세스의 일부입니다. 여기서는 제공된 기본 프로젝트를 사용하여 알 수 없는 프로젝트 ID를 사용합니다. 기본 프로젝트가 제공되지 않은 경우 상위 경로 기본값은 organizations/unknown
입니다.
다음 제약조건을 추가하여 알 수 없는 상위 항목을 차단할 수 있습니다.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: GCPAlwaysViolatesConstraintV1
metadata:
name: disallow_unknown_ancestry
annotations:
description: |
Unknown ancestry is not allowed; use --project=<project> to set a
default ancestry
spec:
severity: high
match:
ancestries:
- "organizations/unknown"
parameters: {}
지원되는 리소스
모든 Terraform 제공업체에서 Terraform 리소스에 대한 리소스 변경 제약조건을 만들 수 있습니다.