Add end-to-end tests for project module (#1823)

* Add end-to-end tests for project module
* Add inventory to data tests
* Add files to end-to-end test cases
* Review fixes - use named groups

---------

Co-authored-by: Ludovico Magnocavallo <ludomagno@google.com>
This commit is contained in:
Wiktor Niesiobędzki
2023-11-03 18:04:19 +01:00
committed by GitHub
parent c501c657ec
commit fe485414e6
24 changed files with 827 additions and 293 deletions

View File

@@ -516,7 +516,7 @@ module "kms-vm-example" {
}
encryption = {
encrypt_boot = true
kms_key_self_link = var.kms_key.self_link
kms_key_self_link = var.kms_key.id
}
}
# tftest modules=1 resources=3 inventory=cmek.yaml

View File

@@ -11,15 +11,16 @@ This module implements the creation and management of one GCP project including
- [Authoritative IAM](#authoritative-iam)
- [Additive IAM](#additive-iam)
- [Service Identities and Authoritative IAM](#service-identities-and-authoritative-iam)
- [Service Identities Requiring Manual Iam Grants](#service-identities-requiring-manual-iam-grants)
- [Service Identities Requiring Manual IAM Grants](#service-identities-requiring-manual-iam-grants)
- [Shared VPC](#shared-vpc)
- [Organization Policies](#organization-policies)
- [Organization Policy Factory](#organization-policy-factory)
- [Log Sinks](#log-sinks)
- [Data Access Logs](#data-access-logs)
- [Cloud Kms Encryption Keys](#cloud-kms-encryption-keys)
- [Cloud KMS Encryption Keys](#cloud-kms-encryption-keys)
- [Tags](#tags)
- [Outputs](#outputs)
- [Managing project related configuration without creating it](#managing-project-related-configuration-without-creating-it)
- [Files](#files)
- [Variables](#variables)
- [Outputs](#outputs)
@@ -30,16 +31,16 @@ This module implements the creation and management of one GCP project including
```hcl
module "project" {
source = "./fabric/modules/project"
billing_account = "123456-123456-123456"
name = "myproject"
parent = "folders/1234567890"
prefix = "foo"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
services = [
"container.googleapis.com",
"stackdriver.googleapis.com"
]
}
# tftest modules=1 resources=3 inventory=basic.yaml
# tftest modules=1 resources=3 inventory=basic.yaml e2e
```
## IAM
@@ -65,10 +66,10 @@ locals {
module "project" {
source = "./fabric/modules/project"
billing_account = "123456-123456-123456"
name = "project-example"
parent = "folders/1234567890"
prefix = "foo"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
services = [
"container.googleapis.com",
"stackdriver.googleapis.com"
@@ -87,12 +88,12 @@ The `group_iam` variable uses group email addresses as keys and is a convenient
```hcl
module "project" {
source = "./fabric/modules/project"
billing_account = "123456-123456-123456"
name = "project-example"
parent = "folders/1234567890"
prefix = "foo"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
group_iam = {
"gcp-security-admins@example.com" = [
(var.group_email) = [
"roles/cloudasset.owner",
"roles/cloudsupport.techSupportEditor",
"roles/iam.securityReviewer",
@@ -100,7 +101,7 @@ module "project" {
]
}
}
# tftest modules=1 resources=5 inventory=iam-group.yaml
# tftest modules=1 resources=5 inventory=iam-group.yaml e2e
```
The `iam_bindings` variable behaves like a more verbose version of `iam`, and allows setting binding-level IAM conditions.
@@ -108,10 +109,10 @@ The `iam_bindings` variable behaves like a more verbose version of `iam`, and al
```hcl
module "project" {
source = "./fabric/modules/project"
billing_account = "123456-123456-123456"
name = "project-example"
parent = "folders/1234567890"
prefix = "foo"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
services = [
"container.googleapis.com",
"stackdriver.googleapis.com"
@@ -119,7 +120,7 @@ module "project" {
iam_bindings = {
iam_admin_conditional = {
members = [
"group:test-admins@example.org"
"group:${var.group_email}"
]
role = "roles/resourcemanager.projectIamAdmin"
condition = {
@@ -135,7 +136,7 @@ module "project" {
}
}
}
# tftest modules=1 resources=4 inventory=iam-bindings.yaml
# tftest modules=1 resources=4 inventory=iam-bindings.yaml e2e
```
### Additive IAM
@@ -146,19 +147,22 @@ The `iam_bindings_additive` variable allows setting individual role/principal bi
```hcl
module "project" {
source = "./fabric/modules/project"
name = "project-1"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
services = [
"compute.googleapis.com"
]
iam_bindings_additive = {
group-owner = {
member = "group:p1-owners@example.org"
member = "group:${var.group_email}"
role = "roles/owner"
}
}
}
# tftest modules=1 resources=3 inventory=iam-bindings-additive.yaml
# tftest modules=1 resources=3 inventory=iam-bindings-additive.yaml e2e
```
### Service Identities and Authoritative IAM
@@ -167,23 +171,21 @@ As mentioned above, there are cases where authoritative management of specific I
```hcl
module "project" {
source = "./fabric/modules/project"
name = "project-example"
group_iam = {
"foo@example.com" = [
"roles/editor"
]
}
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
iam = {
"roles/editor" = [
"serviceAccount:${module.project.service_accounts.cloud_services}"
]
}
}
# tftest modules=1 resources=2
# tftest modules=1 resources=2 e2e
```
### Service Identities Requiring Manual Iam Grants
### Service Identities Requiring Manual IAM Grants
The module will create service identities at project creation instead of creating of them at the time of first use. This allows granting these service identities roles in other projects, something which is usually necessary in a Shared VPC context.
@@ -191,15 +193,21 @@ You can grant roles to service identities using the following construct:
```hcl
module "project" {
source = "./fabric/modules/project"
name = "project-example"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
services = [
"apigee.googleapis.com",
]
iam = {
"roles/apigee.serviceAgent" = [
"serviceAccount:${module.project.service_accounts.robots.apigee}"
]
}
}
# tftest modules=1 resources=2
# tftest modules=1 resources=4 e2e
```
This table lists all affected services and roles that you need to grant to service identities
@@ -225,16 +233,26 @@ You can enable Shared VPC Host at the project level and manage project service a
```hcl
module "host-project" {
source = "./fabric/modules/project"
name = "my-host-project"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "host"
parent = var.folder_id
prefix = var.prefix
shared_vpc_host_config = {
enabled = true
}
}
module "service-project" {
source = "./fabric/modules/project"
name = "my-service-project"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "service"
parent = var.folder_id
prefix = var.prefix
services = [
"container.googleapis.com",
"run.googleapis.com"
]
shared_vpc_service_config = {
host_project = module.host-project.project_id
service_identity_iam = {
@@ -250,23 +268,29 @@ module "service-project" {
}
}
}
# tftest modules=2 resources=8 inventory=shared-vpc.yaml
# tftest modules=2 resources=10 inventory=shared-vpc.yaml e2e
```
The module allows also granting necessary permissions in host project to service identities by specifying which services will be used in service project in `grant_iam_for_services`.
```hcl
module "host-project" {
source = "./fabric/modules/project"
name = "my-host-project"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "host"
parent = var.folder_id
prefix = var.prefix
shared_vpc_host_config = {
enabled = true
}
}
module "service-project" {
source = "./fabric/modules/project"
name = "my-service-project"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "service"
parent = var.folder_id
prefix = var.prefix
services = [
"container.googleapis.com",
]
@@ -275,7 +299,7 @@ module "service-project" {
service_iam_grants = module.service-project.services
}
}
# tftest modules=2 resources=9 inventory=shared-vpc-auto-grants.yaml
# tftest modules=2 resources=9 inventory=shared-vpc-auto-grants.yaml e2e
```
## Organization Policies
@@ -285,10 +309,10 @@ To manage organization policies, the `orgpolicy.googleapis.com` service should b
```hcl
module "project" {
source = "./fabric/modules/project"
billing_account = "123456-123456-123456"
name = "project-example"
parent = "folders/1234567890"
prefix = "foo"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
org_policies = {
"compute.disableGuestAttributesAccess" = {
rules = [{ enforce = true }]
@@ -334,7 +358,7 @@ module "project" {
}
}
}
# tftest modules=1 resources=8 inventory=org-policies.yaml
# tftest modules=1 resources=8 inventory=org-policies.yaml e2e
```
### Organization Policy Factory
@@ -348,13 +372,13 @@ The example below deploys a few organization policies split between two YAML fil
```hcl
module "project" {
source = "./fabric/modules/project"
billing_account = "123456-123456-123456"
name = "project-example"
parent = "folders/1234567890"
prefix = "foo"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
org_policies_data_path = "configs/org-policies/"
}
# tftest modules=1 resources=8 files=boolean,list inventory=org-policies.yaml
# tftest modules=1 resources=8 files=boolean,list inventory=org-policies.yaml e2e
```
```yaml
@@ -415,6 +439,7 @@ module "gcs" {
source = "./fabric/modules/gcs"
project_id = var.project_id
name = "gcs_sink"
prefix = var.prefix
force_destroy = true
}
@@ -422,6 +447,7 @@ module "dataset" {
source = "./fabric/modules/bigquery-dataset"
project_id = var.project_id
id = "bq_sink"
options = { delete_contents_on_destroy = true }
}
module "pubsub" {
@@ -433,15 +459,19 @@ module "pubsub" {
module "bucket" {
source = "./fabric/modules/logging-bucket"
parent_type = "project"
parent = "my-project"
parent = var.project_id
id = "bucket"
}
module "project-host" {
source = "./fabric/modules/project"
name = "my-project"
billing_account = "123456-123456-123456"
parent = "folders/1234567890"
name = "project"
billing_account = var.billing_account_id
parent = var.folder_id
prefix = var.prefix
services = [
"logging.googleapis.com"
]
logging_sinks = {
warnings = {
destination = module.gcs.id
@@ -471,7 +501,7 @@ module "project-host" {
no-gce-instances = "resource.type=gce_instance"
}
}
# tftest modules=5 resources=14 inventory=logging.yaml
# tftest modules=5 resources=15 inventory=logging.yaml e2e
```
## Data Access Logs
@@ -483,13 +513,14 @@ This example shows how to set a non-authoritative access log configuration:
```hcl
module "project" {
source = "./fabric/modules/project"
name = "my-project"
billing_account = "123456-123456-123456"
parent = "folders/1234567890"
name = "project"
billing_account = var.billing_account_id
parent = var.folder_id
prefix = var.prefix
logging_data_access = {
allServices = {
# logs for principals listed here will be excluded
ADMIN_READ = ["group:organization-admins@example.org"]
ADMIN_READ = ["group:${var.group_email}"]
}
"storage.googleapis.com" = {
DATA_READ = []
@@ -497,33 +528,34 @@ module "project" {
}
}
}
# tftest modules=1 resources=3 inventory=logging-data-access.yaml
# tftest modules=1 resources=3 inventory=logging-data-access.yaml e2e
```
## Cloud Kms Encryption Keys
## Cloud KMS Encryption Keys
The module offers a simple, centralized way to assign `roles/cloudkms.cryptoKeyEncrypterDecrypter` to service identities.
```hcl
module "project" {
source = "./fabric/modules/project"
name = "my-project"
prefix = "foo"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "project"
prefix = var.prefix
parent = var.folder_id
services = [
"compute.googleapis.com",
"storage.googleapis.com"
]
service_encryption_key_ids = {
compute = [
"projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce",
"projects/kms-central-prj/locations/europe-west4/keyRings/my-keyring/cryptoKeys/europe4-gce"
var.kms_key.id
]
storage = [
"projects/kms-central-prj/locations/europe/keyRings/my-keyring/cryptoKeys/europe-gcs"
var.kms_key.id
]
}
}
# tftest modules=1 resources=7
# tftest modules=1 resources=6 e2e
```
## Tags
@@ -548,7 +580,8 @@ module "org" {
module "project" {
source = "./fabric/modules/project"
name = "test-project"
name = "project"
parent = var.folder_id
tag_bindings = {
env-prod = module.org.tag_values["environment/prod"].id
foo = "tagValues/12345678"
@@ -565,8 +598,11 @@ One non-obvious output is `service_accounts`, which offers a simple way to disco
```hcl
module "project" {
source = "./fabric/modules/project"
name = "project-example"
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "project"
prefix = var.prefix
parent = var.folder_id
services = [
"compute.googleapis.com"
]
@@ -575,9 +611,222 @@ module "project" {
output "compute_robot" {
value = module.project.service_accounts.robots.compute
}
# tftest modules=1 resources=2 inventory:outputs.yaml
# tftest modules=1 resources=2 inventory:outputs.yaml e2e
```
### Managing project related configuration without creating it
The module offers managing all related resources without ever touching the project itself by using `project_create = false`
```hcl
module "create-project" {
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
}
module "project" {
source = "./fabric/modules/project"
depends_on = [module.create-project]
billing_account = var.billing_account_id
name = "project"
parent = var.folder_id
prefix = var.prefix
project_create = false
group_iam = {
(var.group_email) = [
"roles/cloudasset.owner",
"roles/cloudsupport.techSupportEditor",
"roles/iam.securityReviewer",
"roles/logging.admin",
]
}
iam_bindings = {
iam_admin_conditional = {
members = [
"group:${var.group_email}"
]
role = "roles/resourcemanager.projectIamAdmin"
condition = {
title = "delegated_network_user_one"
expression = <<-END
api.getAttribute(
'iam.googleapis.com/modifiedGrantsByRole', []
).hasOnly([
'roles/compute.networkAdmin'
])
END
}
}
}
iam_bindings_additive = {
group-owner = {
member = "group:${var.group_email}"
role = "roles/owner"
}
}
iam = {
"roles/editor" = [
"serviceAccount:${module.project.service_accounts.cloud_services}"
]
"roles/apigee.serviceAgent" = [
"serviceAccount:${module.project.service_accounts.robots.apigee}"
]
}
logging_data_access = {
allServices = {
# logs for principals listed here will be excluded
ADMIN_READ = ["group:${var.group_email}"]
}
"storage.googleapis.com" = {
DATA_READ = []
DATA_WRITE = []
}
}
logging_sinks = {
warnings = {
destination = module.gcs.id
filter = "severity=WARNING"
type = "storage"
}
info = {
destination = module.dataset.id
filter = "severity=INFO"
type = "bigquery"
}
notice = {
destination = module.pubsub.id
filter = "severity=NOTICE"
type = "pubsub"
}
debug = {
destination = module.bucket.id
filter = "severity=DEBUG"
exclusions = {
no-compute = "logName:compute"
}
type = "logging"
}
}
logging_exclusions = {
no-gce-instances = "resource.type=gce_instance"
}
org_policies = {
"compute.disableGuestAttributesAccess" = {
rules = [{ enforce = true }]
}
"compute.skipDefaultNetworkCreation" = {
rules = [{ enforce = true }]
}
"iam.disableServiceAccountKeyCreation" = {
rules = [{ enforce = true }]
}
"iam.disableServiceAccountKeyUpload" = {
rules = [
{
condition = {
expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')"
title = "condition"
description = "test condition"
location = "somewhere"
}
enforce = true
},
{
enforce = false
}
]
}
"iam.allowedPolicyMemberDomains" = {
rules = [{
allow = {
values = ["C0xxxxxxx", "C0yyyyyyy"]
}
}]
}
"compute.trustedImageProjects" = {
rules = [{
allow = {
values = ["projects/my-project"]
}
}]
}
"compute.vmExternalIpAccess" = {
rules = [{ deny = { all = true } }]
}
}
shared_vpc_service_config = {
host_project = module.host-project.project_id
service_iam_grants = module.project.services
service_identity_iam = {
"roles/cloudasset.owner" = [
"cloudservices", "container-engine"
]
}
}
services = [
"apigee.googleapis.com",
"bigquery.googleapis.com",
"container.googleapis.com",
"logging.googleapis.com",
"run.googleapis.com",
"storage.googleapis.com",
]
service_encryption_key_ids = {
compute = [
var.kms_key.id
]
storage = [
var.kms_key.id
]
}
}
module "host-project" {
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "host"
parent = var.folder_id
prefix = var.prefix
shared_vpc_host_config = {
enabled = true
}
}
module "gcs" {
source = "./fabric/modules/gcs"
project_id = var.project_id
name = "gcs_sink"
prefix = var.prefix
force_destroy = true
}
module "dataset" {
source = "./fabric/modules/bigquery-dataset"
project_id = var.project_id
id = "bq_sink"
options = { delete_contents_on_destroy = true }
}
module "pubsub" {
source = "./fabric/modules/pubsub"
project_id = var.project_id
name = "pubsub_sink"
}
module "bucket" {
source = "./fabric/modules/logging-bucket"
parent_type = "project"
parent = var.project_id
id = "bucket"
}
# tftest modules=7 resources=53 inventory=data.yaml e2e
```
<!-- TFDOC OPTS files:1 -->
<!-- BEGIN TFDOC -->
## Files

View File

@@ -69,7 +69,8 @@ resource "google_logging_project_sink" "sink" {
depends_on = [
google_project_iam_binding.authoritative,
google_project_iam_binding.bindings,
google_project_iam_member.bindings
google_project_iam_member.bindings,
google_project_service.project_services
]
}

View File

@@ -18,7 +18,7 @@
service_agent: "service-%s@gcp-sa-adsdatahub.iam.gserviceaccount.com"
- name: "aiplatform"
service_agent: "service-%s@gcp-sa-aiplatform.iam.gserviceaccount.com"
jit: true
jit: true # roles/aiplatform.customCodeServiceAgent
- name: "aiplatform-cc"
service_agent: "service-%s@gcp-sa-aiplatform-cc.iam.gserviceaccount.com"
- name: "alloydb"
@@ -37,7 +37,7 @@
service_agent: "service-%s@gcp-sa-apigateway-mgmt.iam.gserviceaccount.com"
- name: "apigee"
service_agent: "service-%s@gcp-sa-apigee.iam.gserviceaccount.com"
jit: true #roles/apigee.serviceAgent
jit: true # roles/apigee.serviceAgent
- name: "apigeeregistry"
service_agent: "service-%s@gcp-sa-apigeeregistry.iam.gserviceaccount.com"
- name: "appdevelopmentexperience"
@@ -221,7 +221,7 @@
service_agent: "service-%s@gcp-sa-healthcare.iam.gserviceaccount.com"
- name: "iap"
service_agent: "service-%s@gcp-sa-iap.iam.gserviceaccount.com"
jit: true
jit: true # none
- name: "identitytoolkit"
service_agent: "service-%s@gcp-sa-identitytoolkit.iam.gserviceaccount.com"
- name: "ids"
@@ -314,7 +314,7 @@
service_agent: "service-%s@gcp-sa-spectrumsas.iam.gserviceaccount.com"
- name: "secretmanager"
service_agent: "service-%s@gcp-sa-secretmanager.iam.gserviceaccount.com"
jit: true
jit: true # none
- name: "securedlandingzone"
service_agent: "service-%s@gcp-sa-slz.iam.gserviceaccount.com"
- name: "securitycenter-notification"

View File

@@ -18,9 +18,18 @@ import yaml
from pathlib import Path
BASE_PATH = Path(__file__).parent
COUNT_TEST_RE = re.compile(r'# tftest +modules=(\d+) +resources=(\d+)' +
r'(?: +files=([\w@,_-]+))?' +
r'(?: +inventory=([\w\-.]+))?')
COUNT_TEST_RE = re.compile(r'# tftest +modules=(?P<modules>\d+) +resources=(?P<resources>\d+)' +
r'(?: +files=(?P<files>[\w@,_-]+))?' +
r'(?: +inventory=(?P<inventory>[\w\-.]+))?')
def prepare_files(example, test_path, line):
if line is not None:
requested_files = line.split(',')
for f in requested_files:
destination = test_path / example.files[f].path
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(example.files[f].content)
def test_example(plan_validator, tmp_path, example):
@@ -33,21 +42,16 @@ def test_example(plan_validator, tmp_path, example):
if assets_path.exists():
(tmp_path / 'assets').symlink_to(assets_path)
expected_modules = int(match.group(1))
expected_resources = int(match.group(2))
expected_modules = int(match.group("modules"))
expected_resources = int(match.group("resources"))
if match.group(3) is not None:
requested_files = match.group(3).split(',')
for f in requested_files:
destination = tmp_path / example.files[f].path
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(example.files[f].content)
prepare_files(example, tmp_path, match.group("files"))
inventory = []
if match.group(4) is not None:
if match.group("inventory") is not None:
python_test_path = str(example.module).replace('-', '_')
inventory = BASE_PATH.parent / python_test_path / 'examples'
inventory = inventory / match.group(4)
inventory = inventory / match.group("inventory")
# TODO: force plan_validator to never copy files (we're already
# running from a temp dir)

View File

@@ -22,9 +22,13 @@ variable "billing_account_id" {
default = "123456-123456-123456"
}
variable "group_email" {
default = "organization-admins@example.org"
}
variable "kms_key" {
default = {
self_link = "kms_key_self_link"
id = "kms_key_self_link"
}
}

View File

@@ -9,7 +9,7 @@ Prepare following information:
* prepare service account that has necessary permissions (able to assign billing account to project, resource creation etc)
# How does it work
Each test case is provided by additional environment defined in [variables.tf](./variables.tf). This simplifies writing the examples as this follows the same structure as for non-end-to-end tests, and allows multiple, independent and concurrent runs of tests.
Each test case is provided by additional environment defined in [variables.tf](../examples/variables.tf). This simplifies writing the examples as this follows the same structure as for non-end-to-end tests, and allows multiple, independent and concurrent runs of tests.
The test environment can be provisioned automatically during the test run (which now takes ~2 minutes) and destroyed and the end, when of the tests (Option 1 below), which is targeting automated runs in CI/CD pipeline, or can be provisioned manually to reduce test time, which might be typical use case for tests run locally.
@@ -18,6 +18,7 @@ The test environment can be provisioned automatically during the test run (which
## Create `e2e.tfvars` file
```hcl
billing_account = "123456-123456-123456" # billing account id to associate projects
group_email = "group@example.org" # existing group within organization
organization_id = "1234567890" # your organization id
parent = "folders/1234567890" # folder under which test resources will be created
prefix = "your-unique-prefix" # unique prefix for projects
@@ -27,15 +28,17 @@ region = "europe-west4" # region to use
```
And set environment variable pointing to the file:
```bash
export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects, no longer than 7 characters
export TFTEST_E2E_SETUP_TFVARS_PATH=<path to e2e.tfvars file>
```
Or set above variables in environment:
```bash
export TF_VAR_billing_account="123456-123456-123456" # billing account id to associate projects
export TF_VAR_group_email="group@example.org" # existing group within organization
export TF_VAR_organization_id="1234567890" # your organization id
export TF_VAR_parent="folders/1234567890" # folder under which test resources will be created
export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects
export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects, no longer than 7 characters
export TF_VAR_region="europe-west4" # region to use
```
@@ -55,6 +58,7 @@ pytest tests/examples_e2e
In `tests/examples_e2e/setup_module` create `terraform.tfvars` with following values:
```hcl
billing_account = "123456-123456-123456" # billing account id to associate projects
group_email = "group@example.org" # existing group within organization
organization_id = "1234567890" # your organization id
parent = "folders/1234567890" # folder under which test resources will be created
prefix = "your-unique-prefix" # unique prefix for projects
@@ -79,6 +83,7 @@ This will generate also `tests/examples_e2e/setup_module/e2e_tests.tfvars` for y
## Setup your environment
```bash
export TFTEST_E2E_TFVARS_PATH=`pwd`/tests/examples_e2e/setup_module/e2e_tests.tfvars # generated above
export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects, no longer than 7 characters
```
## Run tests

View File

@@ -12,14 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
bucket= "${bucket}"
bucket = "${bucket}"
billing_account_id = "${billing_account_id}"
kms_key= {
self_link = "kms_key_self_link"
kms_key = {
id = "${kms_key_id}"
}
group_email = "${group_email}"
organization_id = "${organization_id}"
folder_id = "${folder_id}"
prefix = "${prefix}"
folder_id = "folders/${folder_id}"
project_id = "${project_id}"
region = "${region}"
service_account = {

View File

@@ -13,11 +13,14 @@
# limitations under the License.
locals {
prefix = "${var.prefix}-${var.timestamp}-${var.suffix}"
prefix = "${var.prefix}-${var.timestamp}${var.suffix}"
services = [
# trimmed down list of services, to be extended as needed
"apigee.googleapis.com",
"bigquery.googleapis.com",
"cloudbuild.googleapis.com",
"cloudfunctions.googleapis.com",
"cloudkms.googleapis.com",
"cloudresourcemanager.googleapis.com",
"compute.googleapis.com",
"iam.googleapis.com",
@@ -77,14 +80,28 @@ resource "google_service_account" "service_account" {
depends_on = [google_project_service.project_service]
}
resource "google_kms_key_ring" "keyring" {
name = "keyring"
project = google_project.project.project_id
location = var.region
depends_on = [google_project_service.project_service]
}
resource "google_kms_crypto_key" "key" {
name = "crypto-key-example"
key_ring = google_kms_key_ring.keyring.id
rotation_period = "100000s"
}
resource "local_file" "terraform_tfvars" {
filename = "e2e_tests.tfvars"
content = templatefile("e2e_tests.tfvars.tftpl", {
bucket = google_storage_bucket.bucket.name
billing_account_id = var.billing_account
organization_id = var.organization_id
folder_id = google_folder.folder.folder_id
prefix = local.prefix
group_email = var.group_email
kms_key_id = google_kms_crypto_key.key.id
organization_id = var.organization_id
project_id = google_project.project.project_id
region = var.region
service_account = {

View File

@@ -15,6 +15,9 @@
variable "billing_account" {
type = string
}
variable "group_email" {
type = string
}
variable "organization_id" {
type = string
}

View File

@@ -14,16 +14,14 @@
import re
from pathlib import Path
from ..examples.test_plan import COUNT_TEST_RE, prepare_files
BASE_PATH = Path(__file__).parent
COUNT_TEST_RE = re.compile(r'# tftest +modules=(\d+) +resources=(\d+)' +
r'(?: +files=([\w@,_-]+))?' +
r'(?: +inventory=([\w\-.]+))?')
def test_example(e2e_validator, tmp_path, examples_e2e, e2e_tfvars_path):
(tmp_path / 'fabric').symlink_to(BASE_PATH.parents[1])
(tmp_path / 'variables.tf').symlink_to(BASE_PATH / 'variables.tf')
(tmp_path / 'variables.tf').symlink_to(BASE_PATH.parent / 'examples' / 'variables.tf')
(tmp_path / 'main.tf').write_text(examples_e2e.code)
assets_path = BASE_PATH.parent / str(examples_e2e.module).replace(
'-', '_') / 'assets'
@@ -31,5 +29,9 @@ def test_example(e2e_validator, tmp_path, examples_e2e, e2e_tfvars_path):
(tmp_path / 'assets').symlink_to(assets_path)
(tmp_path / 'terraform.tfvars').symlink_to(e2e_tfvars_path)
# add files the same way as it is done for examples
if match := COUNT_TEST_RE.search(examples_e2e.code):
prepare_files(examples_e2e, tmp_path, match.group("files"))
e2e_validator(module_path=tmp_path, extra_files=[],
tf_var_files=[(tmp_path / 'terraform.tfvars')])

View File

@@ -1,92 +0,0 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# common variables used for examples
variable "bucket" {
default = "bucket"
}
variable "billing_account_id" {
default = "123456-123456-123456"
}
variable "kms_key" {
default = {
self_link = "kms_key_self_link"
}
}
variable "organization_id" {
default = "organizations/1122334455"
}
variable "folder_id" {
default = "folders/1122334455"
}
variable "prefix" {
default = "test"
}
variable "project_id" {
default = "project-id"
}
variable "region" {
default = "region"
}
variable "service_account" {
default = {
id = "service_account_id"
email = "service_account_email"
iam_email = "service_account_iam_email"
}
}
variable "subnet" {
default = {
name = "subnet_name"
region = "subnet_region"
cidr = "subnet_cidr"
self_link = "subnet_self_link"
}
}
variable "vpc" {
default = {
name = "vpc_name"
self_link = "projects/xxx/global/networks/aaa"
id = "projects/xxx/global/networks/aaa"
}
}
variable "vpc1" {
default = {
name = "vpc_name"
self_link = "projects/xxx/global/networks/bbb"
}
}
variable "vpc2" {
default = {
name = "vpc2_name"
self_link = "projects/xxx/global/networks/ccc"
}
}
variable "zone" {
default = "zone"
}

View File

@@ -298,9 +298,12 @@ def e2e_validator(module_path, extra_files, tf_var_files, basedir=None):
tf.setup(extra_files=extra_files, upgrade=True)
tf_var_files = [(basedir / x).resolve() for x in tf_var_files or []]
# to allow different tests to create projects (or other globally unique resources) with the same name
# bump prefix forward on each test execution
prefix = f'{os.environ.get("TF_VAR_prefix")}-{int(time.time())}{os.environ.get("PYTEST_XDIST_WORKER", "0")[-2:]}'
try:
apply = tf.apply(tf_var_file=tf_var_files)
plan = tf.plan(output=True, tf_var_file=tf_var_files)
apply = tf.apply(tf_var_file=tf_var_files, tf_vars={"prefix": prefix})
plan = tf.plan(output=True, tf_var_file=tf_var_files, tf_vars={"prefix": prefix})
changes = {}
for resource_name, value in plan.resource_changes.items():
if value.get('change', {}).get('actions') != ['no-op']:
@@ -324,7 +327,7 @@ def e2e_validator(module_path, extra_files, tf_var_files, basedir=None):
# If above did not fail, this should not either, but left as a safety check
assert changes == {}, f'Plan not empty for following resources: {", ".join(changes.keys())}'
finally:
destroy = tf.destroy(tf_var_file=tf_var_files)
destroy = tf.destroy(tf_var_file=tf_var_files, tf_vars={'prefix': prefix})
@pytest.fixture(name='e2e_validator')
@@ -371,7 +374,7 @@ def e2e_tfvars_path():
tf = tftest.TerraformTest(test_path, binary=binary)
tf_vars_file = None
tf_vars = {
'suffix': os.environ.get("PYTEST_XDIST_WORKER", "0"),
'suffix': os.environ.get("PYTEST_XDIST_WORKER", "0")[-2:], # take at most 2 last chars for suffix
'timestamp': str(int(time.time()))
}
if 'TFTEST_E2E_SETUP_TFVARS_PATH' in os.environ:

View File

@@ -17,21 +17,21 @@ values:
module.project.google_project.project[0]:
auto_create_network: false
billing_account: 123456-123456-123456
folder_id: '1234567890'
folder_id: '1122334455'
labels: null
name: foo-myproject
name: test-project
org_id: null
project_id: foo-myproject
project_id: test-project
skip_delete: false
module.project.google_project_service.project_services["container.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: foo-myproject
project: test-project
service: container.googleapis.com
module.project.google_project_service.project_services["stackdriver.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: foo-myproject
project: test-project
service: stackdriver.googleapis.com
counts:

View File

@@ -0,0 +1,338 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
values:
module.bucket.google_logging_project_bucket_config.bucket[0]:
bucket_id: bucket
project: project-id
module.create-project.google_project.project[0]:
billing_account: 123456-123456-123456
folder_id: '1122334455'
name: test-project
project_id: test-project
module.dataset.google_bigquery_dataset.default:
dataset_id: bq_sink
delete_contents_on_destroy: true
project: project-id
module.gcs.google_storage_bucket.bucket:
name: test-gcs_sink
project: project-id
module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]:
project: test-host
module.host-project.google_project.project[0]:
billing_account: 123456-123456-123456
folder_id: '1122334455'
name: test-host
project_id: test-host
module.project.data.google_bigquery_default_service_account.bq_sa[0]:
project: test-project
module.project.data.google_project.project[0]:
project_id: test-project
module.project.data.google_storage_project_service_account.gcs_sa[0]:
project: test-project
module.project.google_bigquery_dataset_iam_member.bq-sinks-binding["info"]:
role: roles/bigquery.dataEditor
module.project.google_compute_shared_vpc_service_project.shared_vpc_service[0]:
host_project: test-host
service_project: test-project
module.project.google_kms_crypto_key_iam_member.service_identity_cmek["compute.kms_key_self_link"]:
crypto_key_id: kms_key_self_link
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
module.project.google_kms_crypto_key_iam_member.service_identity_cmek["storage.kms_key_self_link"]:
crypto_key_id: kms_key_self_link
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
module.project.google_logging_project_exclusion.logging-exclusion["no-gce-instances"]:
filter: resource.type=gce_instance
name: no-gce-instances
project: test-project
module.project.google_logging_project_sink.sink["debug"]:
exclusions:
- description: null
disabled: false
filter: logName:compute
name: no-compute
filter: severity=DEBUG
name: debug
project: test-project
module.project.google_logging_project_sink.sink["info"]:
exclusions: []
filter: severity=INFO
name: info
project: test-project
module.project.google_logging_project_sink.sink["notice"]:
destination: pubsub.googleapis.com/projects/project-id/topics/pubsub_sink
disabled: false
exclusions: []
filter: severity=NOTICE
name: notice
project: test-project
module.project.google_logging_project_sink.sink["warnings"]:
destination: storage.googleapis.com/test-gcs_sink
disabled: false
exclusions: []
filter: severity=WARNING
name: warnings
project: test-project
module.project.google_org_policy_policy.default["compute.disableGuestAttributesAccess"]:
name: projects/test-project/policies/compute.disableGuestAttributesAccess
parent: projects/test-project
spec:
- inherit_from_parent: null
rules:
- allow_all: null
condition: []
deny_all: null
enforce: 'TRUE'
values: []
module.project.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]:
name: projects/test-project/policies/compute.skipDefaultNetworkCreation
parent: projects/test-project
spec:
- inherit_from_parent: null
rules:
- allow_all: null
condition: []
deny_all: null
enforce: 'TRUE'
values: []
module.project.google_org_policy_policy.default["compute.trustedImageProjects"]:
name: projects/test-project/policies/compute.trustedImageProjects
parent: projects/test-project
spec:
- inherit_from_parent: null
rules:
- allow_all: null
condition: []
deny_all: null
enforce: null
values:
- allowed_values:
- projects/my-project
denied_values: null
module.project.google_org_policy_policy.default["compute.vmExternalIpAccess"]:
name: projects/test-project/policies/compute.vmExternalIpAccess
parent: projects/test-project
spec:
- inherit_from_parent: null
rules:
- allow_all: null
condition: []
deny_all: 'TRUE'
enforce: null
values: []
module.project.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]:
name: projects/test-project/policies/iam.allowedPolicyMemberDomains
parent: projects/test-project
spec:
- inherit_from_parent: null
rules:
- allow_all: null
condition: []
deny_all: null
enforce: null
values:
- allowed_values:
- C0xxxxxxx
- C0yyyyyyy
denied_values: null
module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]:
name: projects/test-project/policies/iam.disableServiceAccountKeyCreation
parent: projects/test-project
spec:
- inherit_from_parent: null
rules:
- allow_all: null
condition: []
deny_all: null
enforce: 'TRUE'
values: []
module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyUpload"]:
name: projects/test-project/policies/iam.disableServiceAccountKeyUpload
parent: projects/test-project
spec:
- inherit_from_parent: null
rules:
- allow_all: null
condition:
- description: test condition
expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234')
location: somewhere
title: condition
deny_all: null
enforce: 'TRUE'
values: []
- allow_all: null
condition: []
deny_all: null
enforce: 'FALSE'
values: []
module.project.google_project_iam_audit_config.default["allServices"]:
audit_log_config:
- exempted_members:
- group:organization-admins@example.org
log_type: ADMIN_READ
project: test-project
service: allServices
module.project.google_project_iam_audit_config.default["storage.googleapis.com"]:
audit_log_config:
- exempted_members: []
log_type: DATA_READ
- exempted_members: []
log_type: DATA_WRITE
project: test-project
service: storage.googleapis.com
module.project.google_project_iam_binding.authoritative["roles/apigee.serviceAgent"]:
condition: []
project: test-project
role: roles/apigee.serviceAgent
module.project.google_project_iam_binding.authoritative["roles/cloudasset.owner"]:
condition: []
project: test-project
role: roles/cloudasset.owner
module.project.google_project_iam_binding.authoritative["roles/cloudsupport.techSupportEditor"]:
condition: []
project: test-project
role: roles/cloudsupport.techSupportEditor
module.project.google_project_iam_binding.authoritative["roles/editor"]:
condition: []
project: test-project
role: roles/editor
module.project.google_project_iam_binding.authoritative["roles/iam.securityReviewer"]:
condition: []
project: test-project
role: roles/iam.securityReviewer
module.project.google_project_iam_binding.authoritative["roles/logging.admin"]:
condition: []
project: test-project
role: roles/logging.admin
module.project.google_project_iam_binding.bindings["iam_admin_conditional"]:
condition:
- description: null
expression: "api.getAttribute(\n 'iam.googleapis.com/modifiedGrantsByRole',\
\ []\n).hasOnly([\n 'roles/compute.networkAdmin'\n])\n"
title: delegated_network_user_one
members:
- group:organization-admins@example.org
project: test-project
role: roles/resourcemanager.projectIamAdmin
module.project.google_project_iam_member.bindings["group-owner"]:
condition: []
member: group:organization-admins@example.org
project: test-project
role: roles/owner
module.project.google_project_iam_member.bucket-sinks-binding["debug"]:
condition:
- title: debug bucket writer
role: roles/logging.bucketWriter
module.project.google_project_iam_member.shared_vpc_host_robots["roles/cloudasset.owner:cloudservices"]:
condition: []
project: test-host
role: roles/cloudasset.owner
module.project.google_project_iam_member.shared_vpc_host_robots["roles/cloudasset.owner:container-engine"]:
condition: []
project: test-host
role: roles/cloudasset.owner
module.project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:cloudservices"]:
condition: []
project: test-host
role: roles/compute.networkUser
module.project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:container"]:
condition: []
project: test-host
role: roles/compute.networkUser
module.project.google_project_iam_member.shared_vpc_host_robots["roles/compute.securityAdmin:container"]:
condition: []
project: test-host
role: roles/compute.securityAdmin
module.project.google_project_iam_member.shared_vpc_host_robots["roles/container.hostServiceAgentUser:container"]:
condition: []
project: test-host
role: roles/container.hostServiceAgentUser
module.project.google_project_iam_member.shared_vpc_host_robots["roles/vpcaccess.user:run"]:
condition: []
project: test-host
role: roles/vpcaccess.user
module.project.google_project_service.project_services["apigee.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: test-project
service: apigee.googleapis.com
module.project.google_project_service.project_services["bigquery.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: test-project
service: bigquery.googleapis.com
module.project.google_project_service.project_services["container.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: test-project
service: container.googleapis.com
module.project.google_project_service.project_services["logging.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: test-project
service: logging.googleapis.com
module.project.google_project_service.project_services["run.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: test-project
service: run.googleapis.com
module.project.google_project_service.project_services["storage.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: test-project
service: storage.googleapis.com
module.project.google_project_service_identity.jit_si["apigee.googleapis.com"]:
project: test-project
service: apigee.googleapis.com
module.project.google_pubsub_topic_iam_member.pubsub-sinks-binding["notice"]:
condition: []
project: project-id
role: roles/pubsub.publisher
topic: pubsub_sink
module.project.google_storage_bucket_iam_member.gcs-sinks-binding["warnings"]:
bucket: test-gcs_sink
condition: []
role: roles/storage.objectCreator
module.pubsub.google_pubsub_topic.default:
name: pubsub_sink
project: project-id
counts:
google_bigquery_dataset: 1
google_bigquery_dataset_iam_member: 1
google_bigquery_default_service_account: 1
google_compute_shared_vpc_host_project: 1
google_compute_shared_vpc_service_project: 1
google_kms_crypto_key_iam_member: 2
google_logging_project_bucket_config: 1
google_logging_project_exclusion: 1
google_logging_project_sink: 4
google_org_policy_policy: 7
google_project: 3
google_project_iam_audit_config: 2
google_project_iam_binding: 7
google_project_iam_member: 9
google_project_service: 6
google_project_service_identity: 1
google_pubsub_topic: 1
google_pubsub_topic_iam_member: 1
google_storage_bucket: 1
google_storage_bucket_iam_member: 1
google_storage_project_service_account: 1
modules: 7
resources: 53
outputs: {}

View File

@@ -16,29 +16,29 @@ values:
module.project.google_project.project[0]:
auto_create_network: false
billing_account: 123456-123456-123456
folder_id: '1234567890'
folder_id: '1122334455'
labels: null
name: foo-project-example
name: test-project
org_id: null
project_id: foo-project-example
project_id: test-project
skip_delete: false
timeouts: null
module.project.google_project_iam_binding.authoritative["roles/container.hostServiceAgentUser"]:
condition: []
members:
- serviceAccount:my_gke_service_account
project: foo-project-example
project: test-project
role: roles/container.hostServiceAgentUser
module.project.google_project_service.project_services["container.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: foo-project-example
project: test-project
service: container.googleapis.com
timeouts: null
module.project.google_project_service.project_services["stackdriver.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: foo-project-example
project: test-project
service: stackdriver.googleapis.com
timeouts: null

View File

@@ -15,23 +15,23 @@
values:
module.project.google_project.project[0]:
auto_create_network: false
billing_account: null
folder_id: null
billing_account: 123456-123456-123456
folder_id: '1122334455'
labels: null
name: project-1
name: test-project
org_id: null
project_id: project-1
project_id: test-project
skip_delete: false
timeouts: null
module.project.google_project_iam_member.bindings["group-owner"]:
condition: []
member: group:p1-owners@example.org
project: project-1
member: group:organization-admins@example.org
project: test-project
role: roles/owner
module.project.google_project_service.project_services["compute.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: project-1
project: test-project
service: compute.googleapis.com
timeouts: null

View File

@@ -16,11 +16,11 @@ values:
module.project.google_project.project[0]:
auto_create_network: false
billing_account: 123456-123456-123456
folder_id: '1234567890'
folder_id: '1122334455'
labels: null
name: foo-project-example
name: test-project
org_id: null
project_id: foo-project-example
project_id: test-project
skip_delete: false
timeouts: null
module.project.google_project_iam_binding.bindings["iam_admin_conditional"]:
@@ -30,19 +30,19 @@ values:
\ []\n).hasOnly([\n 'roles/compute.networkAdmin'\n])\n"
title: delegated_network_user_one
members:
- group:test-admins@example.org
project: foo-project-example
- group:organization-admins@example.org
project: test-project
role: roles/resourcemanager.projectIamAdmin
module.project.google_project_service.project_services["container.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: foo-project-example
project: test-project
service: container.googleapis.com
timeouts: null
module.project.google_project_service.project_services["stackdriver.googleapis.com"]:
disable_dependent_services: false
disable_on_destroy: false
project: foo-project-example
project: test-project
service: stackdriver.googleapis.com
timeouts: null

View File

@@ -17,26 +17,26 @@ values:
module.project.google_project_iam_binding.authoritative["roles/cloudasset.owner"]:
condition: []
members:
- group:gcp-security-admins@example.com
project: foo-project-example
- group:organization-admins@example.org
project: test-project
role: roles/cloudasset.owner
module.project.google_project_iam_binding.authoritative["roles/cloudsupport.techSupportEditor"]:
condition: []
members:
- group:gcp-security-admins@example.com
project: foo-project-example
- group:organization-admins@example.org
project: test-project
role: roles/cloudsupport.techSupportEditor
module.project.google_project_iam_binding.authoritative["roles/iam.securityReviewer"]:
condition: []
members:
- group:gcp-security-admins@example.com
project: foo-project-example
- group:organization-admins@example.org
project: test-project
role: roles/iam.securityReviewer
module.project.google_project_iam_binding.authoritative["roles/logging.admin"]:
condition: []
members:
- group:gcp-security-admins@example.com
project: foo-project-example
- group:organization-admins@example.org
project: test-project
role: roles/logging.admin
counts:

View File

@@ -16,11 +16,11 @@ values:
module.project.google_project.project[0]:
auto_create_network: false
billing_account: 123456-123456-123456
folder_id: '1234567890'
folder_id: '1122334455'
labels: null
name: my-project
name: test-project
org_id: null
project_id: my-project
project_id: test-project
skip_delete: false
timeouts: null
module.project.google_project_iam_audit_config.default["allServices"]:
@@ -28,7 +28,7 @@ values:
- exempted_members:
- group:organization-admins@example.org
log_type: ADMIN_READ
project: my-project
project: test-project
service: allServices
module.project.google_project_iam_audit_config.default["storage.googleapis.com"]:
audit_log_config:
@@ -36,7 +36,7 @@ values:
log_type: DATA_READ
- exempted_members: []
log_type: DATA_WRITE
project: my-project
project: test-project
service: storage.googleapis.com
counts:

View File

@@ -21,7 +21,7 @@ values:
disabled: null
filter: resource.type=gce_instance
name: no-gce-instances
project: my-project
project: test-project
module.project-host.google_logging_project_sink.sink["debug"]:
description: debug (Terraform-managed).
disabled: false
@@ -32,7 +32,7 @@ values:
name: no-compute
filter: severity=DEBUG
name: debug
project: my-project
project: test-project
unique_writer_identity: true
module.project-host.google_logging_project_sink.sink["info"]:
description: info (Terraform-managed).
@@ -40,7 +40,7 @@ values:
exclusions: []
filter: severity=INFO
name: info
project: my-project
project: test-project
unique_writer_identity: true
module.project-host.google_logging_project_sink.sink["notice"]:
description: notice (Terraform-managed).
@@ -48,25 +48,25 @@ values:
exclusions: []
filter: severity=NOTICE
name: notice
project: my-project
project: test-project
unique_writer_identity: true
module.project-host.google_logging_project_sink.sink["warnings"]:
description: warnings (Terraform-managed).
destination: storage.googleapis.com/gcs_sink
destination: storage.googleapis.com/test-gcs_sink
disabled: false
exclusions: []
filter: severity=WARNING
name: warnings
project: my-project
project: test-project
unique_writer_identity: true
module.project-host.google_project.project[0]:
auto_create_network: false
billing_account: 123456-123456-123456
folder_id: '1234567890'
folder_id: '1122334455'
labels: null
name: my-project
name: test-project
org_id: null
project_id: my-project
project_id: test-project
skip_delete: false
module.project-host.google_project_iam_member.bucket-sinks-binding["debug"]:
condition:
@@ -76,7 +76,7 @@ values:
condition: []
role: roles/pubsub.publisher
module.project-host.google_storage_bucket_iam_member.gcs-sinks-binding["warnings"]:
bucket: gcs_sink
bucket: test-gcs_sink
condition: []
role: roles/storage.objectCreator

View File

@@ -14,8 +14,8 @@
values:
module.project.google_org_policy_policy.default["compute.disableGuestAttributesAccess"]:
name: projects/foo-project-example/policies/compute.disableGuestAttributesAccess
parent: projects/foo-project-example
name: projects/test-project/policies/compute.disableGuestAttributesAccess
parent: projects/test-project
spec:
- inherit_from_parent: null
reset: null
@@ -26,8 +26,8 @@ values:
enforce: 'TRUE'
values: []
module.project.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]:
name: projects/foo-project-example/policies/compute.skipDefaultNetworkCreation
parent: projects/foo-project-example
name: projects/test-project/policies/compute.skipDefaultNetworkCreation
parent: projects/test-project
spec:
- inherit_from_parent: null
reset: null
@@ -38,8 +38,8 @@ values:
enforce: 'TRUE'
values: []
module.project.google_org_policy_policy.default["compute.trustedImageProjects"]:
name: projects/foo-project-example/policies/compute.trustedImageProjects
parent: projects/foo-project-example
name: projects/test-project/policies/compute.trustedImageProjects
parent: projects/test-project
spec:
- inherit_from_parent: null
reset: null
@@ -53,8 +53,8 @@ values:
- projects/my-project
denied_values: null
module.project.google_org_policy_policy.default["compute.vmExternalIpAccess"]:
name: projects/foo-project-example/policies/compute.vmExternalIpAccess
parent: projects/foo-project-example
name: projects/test-project/policies/compute.vmExternalIpAccess
parent: projects/test-project
spec:
- inherit_from_parent: null
reset: null
@@ -65,8 +65,8 @@ values:
enforce: null
values: []
module.project.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]:
name: projects/foo-project-example/policies/iam.allowedPolicyMemberDomains
parent: projects/foo-project-example
name: projects/test-project/policies/iam.allowedPolicyMemberDomains
parent: projects/test-project
spec:
- inherit_from_parent: null
reset: null
@@ -81,8 +81,8 @@ values:
- C0yyyyyyy
denied_values: null
module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]:
name: projects/foo-project-example/policies/iam.disableServiceAccountKeyCreation
parent: projects/foo-project-example
name: projects/test-project/policies/iam.disableServiceAccountKeyCreation
parent: projects/test-project
spec:
- inherit_from_parent: null
reset: null
@@ -93,8 +93,8 @@ values:
enforce: 'TRUE'
values: []
module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyUpload"]:
name: projects/foo-project-example/policies/iam.disableServiceAccountKeyUpload
parent: projects/foo-project-example
name: projects/test-project/policies/iam.disableServiceAccountKeyUpload
parent: projects/test-project
spec:
- inherit_from_parent: null
reset: null
@@ -115,10 +115,10 @@ values:
values: []
module.project.google_project.project[0]:
billing_account: 123456-123456-123456
folder_id: '1234567890'
name: foo-project-example
folder_id: '1122334455'
name: test-project
org_id: null
project_id: foo-project-example
project_id: test-project
counts:
google_org_policy_policy: 7

View File

@@ -14,25 +14,25 @@
values:
module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]:
project: my-host-project
project: test-host
module.host-project.google_project.project[0]:
project_id: my-host-project
project_id: test-host
module.service-project.google_compute_shared_vpc_service_project.shared_vpc_service[0]:
host_project: my-host-project
service_project: my-service-project
host_project: test-host
service_project: test-service
module.service-project.google_project.project[0]:
project_id: my-service-project
project_id: test-service
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:cloudservices"]:
condition: []
project: my-host-project
project: test-host
role: roles/compute.networkUser
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:container"]:
condition: []
project: my-host-project
project: test-host
role: roles/compute.networkUser
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/container.hostServiceAgentUser:container"]:
condition: []
project: my-host-project
project: test-host
role: roles/container.hostServiceAgentUser
counts:

View File

@@ -14,29 +14,29 @@
values:
module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]:
project: my-host-project
project: test-host
module.host-project.google_project.project[0]:
project_id: my-host-project
project_id: test-host
module.service-project.google_compute_shared_vpc_service_project.shared_vpc_service[0]:
host_project: my-host-project
service_project: my-service-project
host_project: test-host
service_project: test-service
module.service-project.google_project.project[0]:
project_id: my-service-project
project_id: test-service
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:cloudservices"]:
condition: []
project: my-host-project
project: test-host
role: roles/compute.networkUser
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:container-engine"]:
condition: []
project: my-host-project
project: test-host
role: roles/compute.networkUser
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/container.hostServiceAgentUser:container-engine"]:
condition: []
project: my-host-project
project: test-host
role: roles/container.hostServiceAgentUser
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/vpcaccess.user:cloudrun"]:
condition: []
project: my-host-project
project: test-host
role: roles/vpcaccess.user
counts: