From c89e8361195951a52214751f2499c53380e08a95 Mon Sep 17 00:00:00 2001 From: Wilfred Date: Thu, 8 Oct 2020 16:09:08 +0200 Subject: [PATCH 01/11] add workload identity federation --- products/iam/api.yaml | 237 +++++++++++++++++- products/iam/terraform.yaml | 20 ++ third_party/terraform/utils/config.go.erb | 2 - .../provider_handwritten_endpoint.go.erb | 11 - .../guides/provider_reference.html.markdown | 2 +- 5 files changed, 257 insertions(+), 15 deletions(-) create mode 100644 products/iam/terraform.yaml diff --git a/products/iam/api.yaml b/products/iam/api.yaml index 9a7b00df287b..d438fcca3ee0 100644 --- a/products/iam/api.yaml +++ b/products/iam/api.yaml @@ -20,6 +20,9 @@ versions: - !ruby/object:Api::Product::Version name: ga base_url: https://iam.googleapis.com/v1/ + - !ruby/object:Api::Product::Version + name: beta + base_url: https://iam.googleapis.com/v1beta/ scopes: - https://www.googleapis.com/auth/iam apis_required: @@ -195,4 +198,236 @@ objects: - !ruby/object:Api::Type::Boolean name: 'deleted' description: The current deleted state of the role - output: true \ No newline at end of file + output: true + - !ruby/object:Api::Resource + name: 'WorkloadIdentityPool' + min_version: beta + base_url: projects/{{project}}/locations/global/workloadIdentityPools + create_url: projects/{{project}}/locations/global/workloadIdentityPools?workloadIdentityPoolId={{id}} + description: | + Represents a collection of external workload identities. You can define IAM policies to + grant these identities access to Google Cloud resources. + update_mask: true + async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: 'name' + base_url: '{{op_id}}' + wait_ms: 1000 + result: !ruby/object:Api::OpAsync::Result + path: 'response' + resource_inside_response: true + status: !ruby/object:Api::OpAsync::Status + path: 'done' + complete: True + allowed: + - True + - False + error: !ruby/object:Api::OpAsync::Error + path: 'error' + message: 'message' + properties: + - !ruby/object:Api::Type::Enum + name: 'state' + description: | + The state of the pool. + STATE_UNSPECIFIED: State unspecified. + ACTIVE: The pool is active, and may be used in Google Cloud policies. + DELETED: The pool is soft-deleted. Soft-deleted pools are permanently deleted after + approximately 30 days. You can restore a soft-deleted pool using + UndeleteWorkloadIdentityPool. You cannot reuse the ID of a soft-deleted pool until it is + permanently deleted. While a pool is deleted, you cannot use it to exchange tokens, or + use existing tokens to access resources. If the pool is undeleted, existing tokens grant + access again. + output: true + values: + - :STATE_UNSPECIFIED + - :ACTIVE + - :DELETED + - !ruby/object:Api::Type::String + name: 'displayName' + description: A display name for the pool. Cannot exceed 32 characters. + - !ruby/object:Api::Type::String + name: 'description' + description: A description of the pool. Cannot exceed 256 characters. + - !ruby/object:Api::Type::String + name: 'name' + description: The resource name of the pool. + output: true + - !ruby/object:Api::Type::Boolean + name: 'disabled' + description: | + Whether the pool is disabled. You cannot use a disabled pool to exchange tokens, or use + existing tokens to access resources. If the pool is re-enabled, existing tokens grant + access again. + - !ruby/object:Api::Resource + name: 'WorkloadIdentityPoolProvider' + min_version: beta + base_url: projects/{{project}}/locations/global/workloadIdentityPools/{{pool}}/providers + create_url: projects/{{project}}/locations/global/workloadIdentityPools/{{pool}}/providers?workloadIdentityPoolProviderId={{id}} + description: A configuration for an external identity provider. + update_mask: true + async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: 'name' + base_url: '{{op_id}}' + wait_ms: 1000 + result: !ruby/object:Api::OpAsync::Result + path: 'response' + resource_inside_response: true + status: !ruby/object:Api::OpAsync::Status + path: 'done' + complete: True + allowed: + - True + - False + error: !ruby/object:Api::OpAsync::Error + path: 'error' + message: 'message' + properties: + - !ruby/object:Api::Type::NestedObject + name: aws + description: An Amazon Web Services identity provider. + properties: + - !ruby/object:Api::Type::String + name: accountId + description: The AWS account ID. + required: true + - !ruby/object:Api::Type::String + name: 'name' + description: The resource name of the provider. + output: true + - !ruby/object:Api::Type::String + name: 'attributeCondition' + description: | + [A Common Expression Language](https://opensource.google/projects/cel) expression, in + plain text, to restrict what otherwise valid authentication credentials issued by the + provider should not be accepted. + + The expression must output a boolean representing whether to allow the federation. + + The following keywords may be referenced in the expressions: + * `assertion`: JSON representing the authentication credential issued by the provider. + * `google`: The Google attributes mapped from the assertion in the `attribute_mappings`. + * `attribute`: The custom attributes mapped from the assertion in the `attribute_mappings`. + + The maximum length of the attribute condition expression is 4096 characters. If + unspecified, all valid authentication credential are accepted. + + The following example shows how to only allow credentials with a mapped `google.groups` + value of `admins`: + ``` + "'admins' in google.groups" + ``` + - !ruby/object:Api::Type::String + name: 'description' + description: A description for the provider. Cannot exceed 256 characters. + - !ruby/object:Api::Type::String + name: 'displayName' + description: A display name for the provider. Cannot exceed 32 characters. + - !ruby/object:Api::Type::KeyValuePairs + name: 'attributeMapping' + description: | + Maps attributes from authentication credentials issued by an external identity provider + to Google Cloud attributes, such as `subject` and `segment`. + + Each key must be a string specifying the Google Cloud IAM attribute to map to. + + The following keys are supported: + * `google.subject`: The principal IAM is authenticating. You can reference this value + in IAM bindings. This is also the subject that appears in Cloud Logging logs. + Cannot exceed 127 characters. + * `google.groups`: Groups the external identity belongs to. You can grant groups + access to resources using an IAM `principalSet` binding; access applies to all + members of the group. + + You can also provide custom attributes by specifying `attribute.{custom_attribute}`, + where `{custom_attribute}` is the name of the custom attribute to be mapped. You can + define a maximum of 50 custom attributes. The maximum length of a mapped attribute key + is 100 characters, and the key may only contain the characters [a-z0-9_]. + + You can reference these attributes in IAM policies to define fine-grained access for a + workload to Google Cloud resources. For example: + * `google.subject`: + `principal://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/subject/{value}` + * `google.groups`: + `principalSet://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/group/{value}` + * `attribute.{custom_attribute}`: + `principalSet://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/attribute.{custom_attribute}/{value}` + + Each value must be a [Common Expression Language](https://opensource.google/projects/cel) + function that maps an identity provider credential to the normalized attribute specified + by the corresponding map key. + + You can use the `assertion` keyword in the expression to access a JSON representation of + the authentication credential issued by the provider. + + The maximum length of an attribute mapping expression is 2048 characters. When evaluated, + the total size of all mapped attributes must not exceed 8KB. + + For AWS providers, the following rules apply: + - If no attribute mapping is defined, the following default mapping applies: + ``` + { + "google.subject":"assertion.arn", + "attribute.aws_role": + "assertion.arn.contains('assumed-role')" + " ? assertion.arn.extract('{account_arn}assumed-role/')" + " + 'assumed-role/'" + " + assertion.arn.extract('assumed-role/{role_name}/')" + " : assertion.arn", + } + ``` + - If any custom attribute mappings are defined, they must include a mapping to the + `google.subject` attribute. + + For OIDC providers, the following rules apply: + - Custom attribute mappings must be defined, and must include a mapping to the + `google.subject` attribute. For example, the following maps the `sub` claim of the + incoming credential to the `subject` attribute on a Google token. + ``` + {"google.subject": "assertion.sub"} + ``` + - !ruby/object:Api::Type::NestedObject + name: oidc + description: An OpenId Connect 1.0 identity provider. + properties: + - !ruby/object:Api::Type::Array + name: allowedAudiences + item_type: Api::Type::String + description: | + Acceptable values for the `aud` field (audience) in the OIDC token. Token exchange + requests are rejected if the token audience does not match one of the configured + values. Each audience may be at most 256 characters. A maximum of 10 audiences may + be configured. + + If this list is empty, the OIDC token audience must be equal to the full canonical + resource name of the WorkloadIdentityPoolProvider, with or without the HTTPS prefix. + For example: + ``` + //iam.googleapis.com/projects//locations//workloadIdentityPools//providers/ + https://iam.googleapis.com/projects//locations//workloadIdentityPools//providers/ + ``` + - !ruby/object:Api::Type::String + name: issuerUri + description: The OIDC issuer URL. + required: true + - !ruby/object:Api::Type::Enum + name: 'state' + description: | + The state of the provider. + STATE_UNSPECIFIED: State unspecified. + ACTIVE: The provider is active, and may be used to validate authentication credentials. + DELETED: The provider is soft-deleted. Soft-deleted providers are permanently deleted + after approximately 30 days. You can restore a soft-deleted provider using + UndeleteWorkloadIdentityPoolProvider. You cannot reuse the ID of a soft-deleted provider + until it is permanently deleted. + output: true + values: + - :STATE_UNSPECIFIED + - :ACTIVE + - :DELETED + - !ruby/object:Api::Type::Boolean + name: 'disabled' + description: | + Whether the provider is disabled. You cannot use a disabled provider to exchange tokens. + However, existing tokens still grant access. diff --git a/products/iam/terraform.yaml b/products/iam/terraform.yaml new file mode 100644 index 000000000000..512325c57ba8 --- /dev/null +++ b/products/iam/terraform.yaml @@ -0,0 +1,20 @@ +# Copyright 2020 Google Inc. +# 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. + +--- !ruby/object:Provider::Terraform::Config +# This is for copying files over +files: !ruby/object:Provider::Config::Files + # These files have templating (ERB) code that will be run. + # This is usually to add licensing info, autogeneration notices, etc. + compile: +<%= lines(indent(compile('provider/terraform/product~compile.yaml'), 4)) -%> diff --git a/third_party/terraform/utils/config.go.erb b/third_party/terraform/utils/config.go.erb index 27a21c63f7aa..4d3ba9b5039b 100644 --- a/third_party/terraform/utils/config.go.erb +++ b/third_party/terraform/utils/config.go.erb @@ -104,7 +104,6 @@ type Config struct { DnsBetaBasePath string IamCredentialsBasePath string ResourceManagerV2Beta1BasePath string - IAMBasePath string CloudIoTBasePath string ServiceNetworkingBasePath string StorageTransferBasePath string @@ -867,7 +866,6 @@ func ConfigureBasePaths(c *Config) { c.DnsBetaBasePath = DnsBetaDefaultBasePath c.IamCredentialsBasePath = IamCredentialsDefaultBasePath c.ResourceManagerV2Beta1BasePath = ResourceManagerV2Beta1DefaultBasePath - c.IAMBasePath = IAMDefaultBasePath c.ServiceNetworkingBasePath = ServiceNetworkingDefaultBasePath c.BigQueryBasePath = BigQueryDefaultBasePath c.StorageTransferBasePath = StorageTransferDefaultBasePath diff --git a/third_party/terraform/utils/provider_handwritten_endpoint.go.erb b/third_party/terraform/utils/provider_handwritten_endpoint.go.erb index 52a537369a8b..03b4b263f25c 100644 --- a/third_party/terraform/utils/provider_handwritten_endpoint.go.erb +++ b/third_party/terraform/utils/provider_handwritten_endpoint.go.erb @@ -104,17 +104,6 @@ var DnsBetaCustomEndpointEntry = &schema.Schema{ }, DnsBetaDefaultBasePath), } -var IAMDefaultBasePath = "https://iam.googleapis.com/v1/" -var IAMCustomEndpointEntryKey = "iam_custom_endpoint" -var IAMCustomEndpointEntry = &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateCustomEndpoint, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{ - "GOOGLE_IAM_CUSTOM_ENDPOINT", - }, IAMDefaultBasePath), -} - var IamCredentialsDefaultBasePath = "https://iamcredentials.googleapis.com/v1/" var IamCredentialsCustomEndpointEntryKey = "iam_credentials_custom_endpoint" var IamCredentialsCustomEndpointEntry = &schema.Schema{ diff --git a/third_party/terraform/website/docs/guides/provider_reference.html.markdown b/third_party/terraform/website/docs/guides/provider_reference.html.markdown index 63cfe899dfa0..ed833a436cb2 100644 --- a/third_party/terraform/website/docs/guides/provider_reference.html.markdown +++ b/third_party/terraform/website/docs/guides/provider_reference.html.markdown @@ -304,7 +304,7 @@ be used for configuration are below: * `dns_beta_custom_endpoint` (`GOOGLE_DNS_BETA_CUSTOM_ENDPOINT`) - `https://www.googleapis.com/dns/v1beta2/` * `filestore_custom_endpoint` (`GOOGLE_FILESTORE_CUSTOM_ENDPOINT`) - `https://file.googleapis.com/v1/` * `firestore_custom_endpoint` (`GOOGLE_FIRESTORE_CUSTOM_ENDPOINT`) - `https://firestore.googleapis.com/v1/` -* `iam_custom_endpoint` (`GOOGLE_IAM_CUSTOM_ENDPOINT`) - `https://iam.googleapis.com/v1/` +* `iam_custom_endpoint` (`GOOGLE_IAM_CUSTOM_ENDPOINT`) - `https://iam.googleapis.com/v1beta/` * `iam_credentials_custom_endpoint` (`GOOGLE_IAM_CREDENTIALS_CUSTOM_ENDPOINT`) - `https://iamcredentials.googleapis.com/v1/` * `kms_custom_endpoint` (`GOOGLE_KMS_CUSTOM_ENDPOINT`) - `https://cloudkms.googleapis.com/v1/` * `logging_custom_endpoint` (`GOOGLE_LOGGING_CUSTOM_ENDPOINT`) - `https://logging.googleapis.com/v2/` From 8ce2623c047920c9f1571817d119f434b21b1f91 Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 9 Oct 2020 12:54:04 +0200 Subject: [PATCH 02/11] remove WorkloadIdentityPoolProvider for now so we first focus on a single new resource --- products/iam/api.yaml | 172 ------------------------------------------ 1 file changed, 172 deletions(-) diff --git a/products/iam/api.yaml b/products/iam/api.yaml index d438fcca3ee0..3b2640bbf081 100644 --- a/products/iam/api.yaml +++ b/products/iam/api.yaml @@ -259,175 +259,3 @@ objects: Whether the pool is disabled. You cannot use a disabled pool to exchange tokens, or use existing tokens to access resources. If the pool is re-enabled, existing tokens grant access again. - - !ruby/object:Api::Resource - name: 'WorkloadIdentityPoolProvider' - min_version: beta - base_url: projects/{{project}}/locations/global/workloadIdentityPools/{{pool}}/providers - create_url: projects/{{project}}/locations/global/workloadIdentityPools/{{pool}}/providers?workloadIdentityPoolProviderId={{id}} - description: A configuration for an external identity provider. - update_mask: true - async: !ruby/object:Api::OpAsync - operation: !ruby/object:Api::OpAsync::Operation - path: 'name' - base_url: '{{op_id}}' - wait_ms: 1000 - result: !ruby/object:Api::OpAsync::Result - path: 'response' - resource_inside_response: true - status: !ruby/object:Api::OpAsync::Status - path: 'done' - complete: True - allowed: - - True - - False - error: !ruby/object:Api::OpAsync::Error - path: 'error' - message: 'message' - properties: - - !ruby/object:Api::Type::NestedObject - name: aws - description: An Amazon Web Services identity provider. - properties: - - !ruby/object:Api::Type::String - name: accountId - description: The AWS account ID. - required: true - - !ruby/object:Api::Type::String - name: 'name' - description: The resource name of the provider. - output: true - - !ruby/object:Api::Type::String - name: 'attributeCondition' - description: | - [A Common Expression Language](https://opensource.google/projects/cel) expression, in - plain text, to restrict what otherwise valid authentication credentials issued by the - provider should not be accepted. - - The expression must output a boolean representing whether to allow the federation. - - The following keywords may be referenced in the expressions: - * `assertion`: JSON representing the authentication credential issued by the provider. - * `google`: The Google attributes mapped from the assertion in the `attribute_mappings`. - * `attribute`: The custom attributes mapped from the assertion in the `attribute_mappings`. - - The maximum length of the attribute condition expression is 4096 characters. If - unspecified, all valid authentication credential are accepted. - - The following example shows how to only allow credentials with a mapped `google.groups` - value of `admins`: - ``` - "'admins' in google.groups" - ``` - - !ruby/object:Api::Type::String - name: 'description' - description: A description for the provider. Cannot exceed 256 characters. - - !ruby/object:Api::Type::String - name: 'displayName' - description: A display name for the provider. Cannot exceed 32 characters. - - !ruby/object:Api::Type::KeyValuePairs - name: 'attributeMapping' - description: | - Maps attributes from authentication credentials issued by an external identity provider - to Google Cloud attributes, such as `subject` and `segment`. - - Each key must be a string specifying the Google Cloud IAM attribute to map to. - - The following keys are supported: - * `google.subject`: The principal IAM is authenticating. You can reference this value - in IAM bindings. This is also the subject that appears in Cloud Logging logs. - Cannot exceed 127 characters. - * `google.groups`: Groups the external identity belongs to. You can grant groups - access to resources using an IAM `principalSet` binding; access applies to all - members of the group. - - You can also provide custom attributes by specifying `attribute.{custom_attribute}`, - where `{custom_attribute}` is the name of the custom attribute to be mapped. You can - define a maximum of 50 custom attributes. The maximum length of a mapped attribute key - is 100 characters, and the key may only contain the characters [a-z0-9_]. - - You can reference these attributes in IAM policies to define fine-grained access for a - workload to Google Cloud resources. For example: - * `google.subject`: - `principal://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/subject/{value}` - * `google.groups`: - `principalSet://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/group/{value}` - * `attribute.{custom_attribute}`: - `principalSet://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/attribute.{custom_attribute}/{value}` - - Each value must be a [Common Expression Language](https://opensource.google/projects/cel) - function that maps an identity provider credential to the normalized attribute specified - by the corresponding map key. - - You can use the `assertion` keyword in the expression to access a JSON representation of - the authentication credential issued by the provider. - - The maximum length of an attribute mapping expression is 2048 characters. When evaluated, - the total size of all mapped attributes must not exceed 8KB. - - For AWS providers, the following rules apply: - - If no attribute mapping is defined, the following default mapping applies: - ``` - { - "google.subject":"assertion.arn", - "attribute.aws_role": - "assertion.arn.contains('assumed-role')" - " ? assertion.arn.extract('{account_arn}assumed-role/')" - " + 'assumed-role/'" - " + assertion.arn.extract('assumed-role/{role_name}/')" - " : assertion.arn", - } - ``` - - If any custom attribute mappings are defined, they must include a mapping to the - `google.subject` attribute. - - For OIDC providers, the following rules apply: - - Custom attribute mappings must be defined, and must include a mapping to the - `google.subject` attribute. For example, the following maps the `sub` claim of the - incoming credential to the `subject` attribute on a Google token. - ``` - {"google.subject": "assertion.sub"} - ``` - - !ruby/object:Api::Type::NestedObject - name: oidc - description: An OpenId Connect 1.0 identity provider. - properties: - - !ruby/object:Api::Type::Array - name: allowedAudiences - item_type: Api::Type::String - description: | - Acceptable values for the `aud` field (audience) in the OIDC token. Token exchange - requests are rejected if the token audience does not match one of the configured - values. Each audience may be at most 256 characters. A maximum of 10 audiences may - be configured. - - If this list is empty, the OIDC token audience must be equal to the full canonical - resource name of the WorkloadIdentityPoolProvider, with or without the HTTPS prefix. - For example: - ``` - //iam.googleapis.com/projects//locations//workloadIdentityPools//providers/ - https://iam.googleapis.com/projects//locations//workloadIdentityPools//providers/ - ``` - - !ruby/object:Api::Type::String - name: issuerUri - description: The OIDC issuer URL. - required: true - - !ruby/object:Api::Type::Enum - name: 'state' - description: | - The state of the provider. - STATE_UNSPECIFIED: State unspecified. - ACTIVE: The provider is active, and may be used to validate authentication credentials. - DELETED: The provider is soft-deleted. Soft-deleted providers are permanently deleted - after approximately 30 days. You can restore a soft-deleted provider using - UndeleteWorkloadIdentityPoolProvider. You cannot reuse the ID of a soft-deleted provider - until it is permanently deleted. - output: true - values: - - :STATE_UNSPECIFIED - - :ACTIVE - - :DELETED - - !ruby/object:Api::Type::Boolean - name: 'disabled' - description: | - Whether the provider is disabled. You cannot use a disabled provider to exchange tokens. - However, existing tokens still grant access. From e0b072012319a5d4d987d024eb9173706b709b73 Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 9 Oct 2020 12:54:25 +0200 Subject: [PATCH 03/11] exclude WorkloadIdentityPool from ansible and inspec --- products/iam/ansible.yaml | 4 ++++ products/iam/inspec.yaml | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/products/iam/ansible.yaml b/products/iam/ansible.yaml index 6f3516381dc5..8721b624c367 100644 --- a/products/iam/ansible.yaml +++ b/products/iam/ansible.yaml @@ -24,6 +24,8 @@ datasources: !ruby/object:Overrides::ResourceOverrides exclude: true OrganizationCustomRole: !ruby/object:Overrides::Ansible::ResourceOverride exclude: true + WorkloadIdentityPool: !ruby/object:Overrides::Ansible::ResourceOverride + exclude: true overrides: !ruby/object:Overrides::ResourceOverrides Role: !ruby/object:Overrides::Ansible::ResourceOverride custom_code: !ruby/object:Provider::Ansible::CustomCode @@ -46,6 +48,8 @@ overrides: !ruby/object:Overrides::ResourceOverrides has_autogenerated_test: false OrganizationCustomRole: !ruby/object:Overrides::Ansible::ResourceOverride exclude: true + WorkloadIdentityPool: !ruby/object:Overrides::Ansible::ResourceOverride + exclude: true files: !ruby/object:Provider::Config::Files resource: <%= lines(indent(compile('provider/ansible/resource~compile.yaml'), 4)) -%> diff --git a/products/iam/inspec.yaml b/products/iam/inspec.yaml index e70c0f862ceb..25f9f3268508 100644 --- a/products/iam/inspec.yaml +++ b/products/iam/inspec.yaml @@ -46,4 +46,6 @@ overrides: !ruby/object:Overrides::ResourceOverrides base_url: organizations/{{org_id}}/roles?view=FULL self_link: organizations/{{org_id}}/roles/{{name}} collection_url_key: roles - privileged: true \ No newline at end of file + privileged: true + WorkloadIdentityPool: !ruby/object:Overrides::Inspec::ResourceOverride + exclude: true From c2ad00ea2efeef3ab5ec5ca990f87d65fd4c6717 Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 9 Oct 2020 15:34:43 +0200 Subject: [PATCH 04/11] do not use reserved property `id` --- products/iam/api.yaml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/products/iam/api.yaml b/products/iam/api.yaml index 3b2640bbf081..cade114fad63 100644 --- a/products/iam/api.yaml +++ b/products/iam/api.yaml @@ -203,7 +203,7 @@ objects: name: 'WorkloadIdentityPool' min_version: beta base_url: projects/{{project}}/locations/global/workloadIdentityPools - create_url: projects/{{project}}/locations/global/workloadIdentityPools?workloadIdentityPoolId={{id}} + create_url: projects/{{project}}/locations/global/workloadIdentityPools?workloadIdentityPoolId={{workload_identity_pool_id}} description: | Represents a collection of external workload identities. You can define IAM policies to grant these identities access to Google Cloud resources. @@ -226,6 +226,15 @@ objects: path: 'error' message: 'message' properties: + - !ruby/object:Api::Type::String + name: 'workloadIdentityPoolId' + description: | + The ID to use for the pool, which becomes the final component of the resource name. This + value should be 4-32 characters, and may contain the characters [a-z0-9-]. The prefix + `gcp-` is reserved for use by Google, and may not be specified. + required: true + input: true + url_param_only: true - !ruby/object:Api::Type::Enum name: 'state' description: | @@ -251,7 +260,9 @@ objects: description: A description of the pool. Cannot exceed 256 characters. - !ruby/object:Api::Type::String name: 'name' - description: The resource name of the pool. + description: | + The resource name of the pool as + `projects//locations/global/workloadIdentityPools/`. output: true - !ruby/object:Api::Type::Boolean name: 'disabled' From cb8e04cd45877c2e413c89b1c5618a6204872a7d Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 9 Oct 2020 15:36:01 +0200 Subject: [PATCH 05/11] do not generate handwritten iam resources --- products/iam/terraform.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/products/iam/terraform.yaml b/products/iam/terraform.yaml index 512325c57ba8..8d2178c73b5f 100644 --- a/products/iam/terraform.yaml +++ b/products/iam/terraform.yaml @@ -12,6 +12,15 @@ # limitations under the License. --- !ruby/object:Provider::Terraform::Config +overrides: !ruby/object:Overrides::ResourceOverrides + Role: !ruby/object:Overrides::Terraform::ResourceOverride + exclude: true + ServiceAccount: !ruby/object:Overrides::Terraform::ResourceOverride + exclude: true + ServiceAccountKey: !ruby/object:Overrides::Terraform::ResourceOverride + exclude: true + OrganizationCustomRole: !ruby/object:Overrides::Terraform::ResourceOverride + exclude: true # This is for copying files over files: !ruby/object:Provider::Config::Files # These files have templating (ERB) code that will be run. From 5b7de59ce6b061aa8e0f2640851c1ea45bce2008 Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 9 Oct 2020 15:36:52 +0200 Subject: [PATCH 06/11] remove custom endpoint for handwritten iam resources as this is no auto-generated --- third_party/terraform/utils/provider.go.erb | 2 -- 1 file changed, 2 deletions(-) diff --git a/third_party/terraform/utils/provider.go.erb b/third_party/terraform/utils/provider.go.erb index 32845a074bf3..60aae5e9e1cf 100644 --- a/third_party/terraform/utils/provider.go.erb +++ b/third_party/terraform/utils/provider.go.erb @@ -158,7 +158,6 @@ func Provider() *schema.Provider { IamCredentialsCustomEndpointEntryKey: IamCredentialsCustomEndpointEntry, ResourceManagerV2Beta1CustomEndpointEntryKey: ResourceManagerV2Beta1CustomEndpointEntry, RuntimeConfigCustomEndpointEntryKey: RuntimeConfigCustomEndpointEntry, - IAMCustomEndpointEntryKey: IAMCustomEndpointEntry, ServiceNetworkingCustomEndpointEntryKey: ServiceNetworkingCustomEndpointEntry, ServiceUsageCustomEndpointEntryKey: ServiceUsageCustomEndpointEntry, StorageTransferCustomEndpointEntryKey: StorageTransferCustomEndpointEntry, @@ -530,7 +529,6 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.IamCredentialsBasePath = d.Get(IamCredentialsCustomEndpointEntryKey).(string) config.ResourceManagerV2Beta1BasePath = d.Get(ResourceManagerV2Beta1CustomEndpointEntryKey).(string) config.RuntimeConfigBasePath = d.Get(RuntimeConfigCustomEndpointEntryKey).(string) - config.IAMBasePath = d.Get(IAMCustomEndpointEntryKey).(string) config.ServiceNetworkingBasePath = d.Get(ServiceNetworkingCustomEndpointEntryKey).(string) config.ServiceUsageBasePath = d.Get(ServiceUsageCustomEndpointEntryKey).(string) config.StorageTransferBasePath = d.Get(StorageTransferCustomEndpointEntryKey).(string) From 071d927b16c51b655d7d38789ac20a82e4575b92 Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 9 Oct 2020 15:37:06 +0200 Subject: [PATCH 07/11] example test --- ...esource_iam_workload_identity_pool_test.go | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 third_party/terraform/tests/resource_iam_workload_identity_pool_test.go diff --git a/third_party/terraform/tests/resource_iam_workload_identity_pool_test.go b/third_party/terraform/tests/resource_iam_workload_identity_pool_test.go new file mode 100644 index 000000000000..3983c5697036 --- /dev/null +++ b/third_party/terraform/tests/resource_iam_workload_identity_pool_test.go @@ -0,0 +1,55 @@ +package google + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIAMWorkloadIdentityPool_example(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "org_domain": getTestOrgDomainFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIAMWorkloadIdentityPool_example(context), + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"project"}, + }, + }, + }) +} + +func testAccIAMWorkloadIdentityPool_example(context map[string]interface{}) string { + return Nprintf(` +resource "google_project" "my_project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" +} + +resource "google_project_service" "my_service" { + project = google_project.my_project.project_id + service = "iam.googleapis.com" +} + +resource "google_iam_workload_identity_pool" "my_pool" { + project = google_project_service.my_service.project + display_name = "Name of pool" + description = "Identity pool for automated test" + disabled = true +} +`, context) +} From 771269d25f985ed2257ff96a7b66a6f5a509a2bc Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 9 Oct 2020 16:08:05 +0200 Subject: [PATCH 08/11] also mention non-beta URL in docs --- .../docs/guides/provider_reference.html.markdown | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/third_party/terraform/website/docs/guides/provider_reference.html.markdown b/third_party/terraform/website/docs/guides/provider_reference.html.markdown index ed833a436cb2..6c52aa542c8b 100644 --- a/third_party/terraform/website/docs/guides/provider_reference.html.markdown +++ b/third_party/terraform/website/docs/guides/provider_reference.html.markdown @@ -126,9 +126,9 @@ resource project for preconditions, quota, and billing, instead of the project the credentials belong to. Not all resources support this- see the documentation for each resource to learn whether it does. -* `billing_project` - (Optional) This fields specifies a project that's used for -preconditions, quota, and billing for requests. All resources that support user project -overrides will use this project instead of the resource's project (if available). This +* `billing_project` - (Optional) This fields specifies a project that's used for +preconditions, quota, and billing for requests. All resources that support user project +overrides will use this project instead of the resource's project (if available). This field is ignored if `user_project_override` is set to false or unset. * `{{service}}_custom_endpoint` - (Optional) The endpoint for a service's APIs, @@ -211,7 +211,7 @@ following ordered by precedence. --- * `billing_project` - (Optional) This fields allows Terraform to set X-Goog-User-Project -for APIs that require a billing project to be specified like Access Context Manager APIs if +for APIs that require a billing project to be specified like Access Context Manager APIs if User ADCs are being used. This can also be specified using the `GOOGLE_BILLING_PROJECT` environment variable. @@ -304,7 +304,7 @@ be used for configuration are below: * `dns_beta_custom_endpoint` (`GOOGLE_DNS_BETA_CUSTOM_ENDPOINT`) - `https://www.googleapis.com/dns/v1beta2/` * `filestore_custom_endpoint` (`GOOGLE_FILESTORE_CUSTOM_ENDPOINT`) - `https://file.googleapis.com/v1/` * `firestore_custom_endpoint` (`GOOGLE_FIRESTORE_CUSTOM_ENDPOINT`) - `https://firestore.googleapis.com/v1/` -* `iam_custom_endpoint` (`GOOGLE_IAM_CUSTOM_ENDPOINT`) - `https://iam.googleapis.com/v1beta/` +* `iam_custom_endpoint` (`GOOGLE_IAM_CUSTOM_ENDPOINT`) - `https://iam.googleapis.com/v1/` | `https://iam.googleapis.com/v1beta/` * `iam_credentials_custom_endpoint` (`GOOGLE_IAM_CREDENTIALS_CUSTOM_ENDPOINT`) - `https://iamcredentials.googleapis.com/v1/` * `kms_custom_endpoint` (`GOOGLE_KMS_CUSTOM_ENDPOINT`) - `https://cloudkms.googleapis.com/v1/` * `logging_custom_endpoint` (`GOOGLE_LOGGING_CUSTOM_ENDPOINT`) - `https://logging.googleapis.com/v2/` @@ -351,12 +351,12 @@ as their versioned counterpart but that won't necessarily always be the case. * `batching` - (Optional) Controls batching for specific GCP request types where users have encountered quota or speed issues using `count` with - resources that affect the same GCP resource (e.g. `google_project_service`). + resources that affect the same GCP resource (e.g. `google_project_service`). It is not used for every resource/request type and can only group parallel similar calls for nodes at a similar traversal time in the graph during `terraform apply` (e.g. resources created using `count` that affect a single - `project`). Thus, it is also bounded by the `terraform` - [`-parallelism`](https://www.terraform.io/docs/commands/apply.html#parallelism-n) + `project`). Thus, it is also bounded by the `terraform` + [`-parallelism`](https://www.terraform.io/docs/commands/apply.html#parallelism-n) flag, as reducing the number of parallel calls will reduce the number of simultaneous requests being added to a batcher. From e73a91983220ee28a5f99ebbe6d5c9d74c88542f Mon Sep 17 00:00:00 2001 From: Wilfred Date: Tue, 13 Oct 2020 21:48:43 +0200 Subject: [PATCH 09/11] split iam and iambeta product --- products/iam/ansible.yaml | 4 - products/iam/api.yaml | 76 +---------------- products/iam/inspec.yaml | 4 +- products/iambeta/api.yaml | 81 +++++++++++++++++++ products/{iam => iambeta}/terraform.yaml | 10 +-- ...m_beta_workload_identity_pool_test.go.erb} | 15 ++-- third_party/terraform/utils/config.go.erb | 2 + third_party/terraform/utils/provider.go.erb | 2 + .../provider_handwritten_endpoint.go.erb | 11 +++ .../guides/provider_reference.html.markdown | 16 ++-- 10 files changed, 113 insertions(+), 108 deletions(-) create mode 100644 products/iambeta/api.yaml rename products/{iam => iambeta}/terraform.yaml (69%) rename third_party/terraform/tests/{resource_iam_workload_identity_pool_test.go => resource_iam_beta_workload_identity_pool_test.go.erb} (70%) diff --git a/products/iam/ansible.yaml b/products/iam/ansible.yaml index 8721b624c367..6f3516381dc5 100644 --- a/products/iam/ansible.yaml +++ b/products/iam/ansible.yaml @@ -24,8 +24,6 @@ datasources: !ruby/object:Overrides::ResourceOverrides exclude: true OrganizationCustomRole: !ruby/object:Overrides::Ansible::ResourceOverride exclude: true - WorkloadIdentityPool: !ruby/object:Overrides::Ansible::ResourceOverride - exclude: true overrides: !ruby/object:Overrides::ResourceOverrides Role: !ruby/object:Overrides::Ansible::ResourceOverride custom_code: !ruby/object:Provider::Ansible::CustomCode @@ -48,8 +46,6 @@ overrides: !ruby/object:Overrides::ResourceOverrides has_autogenerated_test: false OrganizationCustomRole: !ruby/object:Overrides::Ansible::ResourceOverride exclude: true - WorkloadIdentityPool: !ruby/object:Overrides::Ansible::ResourceOverride - exclude: true files: !ruby/object:Provider::Config::Files resource: <%= lines(indent(compile('provider/ansible/resource~compile.yaml'), 4)) -%> diff --git a/products/iam/api.yaml b/products/iam/api.yaml index cade114fad63..9a7b00df287b 100644 --- a/products/iam/api.yaml +++ b/products/iam/api.yaml @@ -20,9 +20,6 @@ versions: - !ruby/object:Api::Product::Version name: ga base_url: https://iam.googleapis.com/v1/ - - !ruby/object:Api::Product::Version - name: beta - base_url: https://iam.googleapis.com/v1beta/ scopes: - https://www.googleapis.com/auth/iam apis_required: @@ -198,75 +195,4 @@ objects: - !ruby/object:Api::Type::Boolean name: 'deleted' description: The current deleted state of the role - output: true - - !ruby/object:Api::Resource - name: 'WorkloadIdentityPool' - min_version: beta - base_url: projects/{{project}}/locations/global/workloadIdentityPools - create_url: projects/{{project}}/locations/global/workloadIdentityPools?workloadIdentityPoolId={{workload_identity_pool_id}} - description: | - Represents a collection of external workload identities. You can define IAM policies to - grant these identities access to Google Cloud resources. - update_mask: true - async: !ruby/object:Api::OpAsync - operation: !ruby/object:Api::OpAsync::Operation - path: 'name' - base_url: '{{op_id}}' - wait_ms: 1000 - result: !ruby/object:Api::OpAsync::Result - path: 'response' - resource_inside_response: true - status: !ruby/object:Api::OpAsync::Status - path: 'done' - complete: True - allowed: - - True - - False - error: !ruby/object:Api::OpAsync::Error - path: 'error' - message: 'message' - properties: - - !ruby/object:Api::Type::String - name: 'workloadIdentityPoolId' - description: | - The ID to use for the pool, which becomes the final component of the resource name. This - value should be 4-32 characters, and may contain the characters [a-z0-9-]. The prefix - `gcp-` is reserved for use by Google, and may not be specified. - required: true - input: true - url_param_only: true - - !ruby/object:Api::Type::Enum - name: 'state' - description: | - The state of the pool. - STATE_UNSPECIFIED: State unspecified. - ACTIVE: The pool is active, and may be used in Google Cloud policies. - DELETED: The pool is soft-deleted. Soft-deleted pools are permanently deleted after - approximately 30 days. You can restore a soft-deleted pool using - UndeleteWorkloadIdentityPool. You cannot reuse the ID of a soft-deleted pool until it is - permanently deleted. While a pool is deleted, you cannot use it to exchange tokens, or - use existing tokens to access resources. If the pool is undeleted, existing tokens grant - access again. - output: true - values: - - :STATE_UNSPECIFIED - - :ACTIVE - - :DELETED - - !ruby/object:Api::Type::String - name: 'displayName' - description: A display name for the pool. Cannot exceed 32 characters. - - !ruby/object:Api::Type::String - name: 'description' - description: A description of the pool. Cannot exceed 256 characters. - - !ruby/object:Api::Type::String - name: 'name' - description: | - The resource name of the pool as - `projects//locations/global/workloadIdentityPools/`. - output: true - - !ruby/object:Api::Type::Boolean - name: 'disabled' - description: | - Whether the pool is disabled. You cannot use a disabled pool to exchange tokens, or use - existing tokens to access resources. If the pool is re-enabled, existing tokens grant - access again. + output: true \ No newline at end of file diff --git a/products/iam/inspec.yaml b/products/iam/inspec.yaml index 25f9f3268508..e70c0f862ceb 100644 --- a/products/iam/inspec.yaml +++ b/products/iam/inspec.yaml @@ -46,6 +46,4 @@ overrides: !ruby/object:Overrides::ResourceOverrides base_url: organizations/{{org_id}}/roles?view=FULL self_link: organizations/{{org_id}}/roles/{{name}} collection_url_key: roles - privileged: true - WorkloadIdentityPool: !ruby/object:Overrides::Inspec::ResourceOverride - exclude: true + privileged: true \ No newline at end of file diff --git a/products/iambeta/api.yaml b/products/iambeta/api.yaml new file mode 100644 index 000000000000..3c8a4cdd82e9 --- /dev/null +++ b/products/iambeta/api.yaml @@ -0,0 +1,81 @@ +# Copyright 2017 Google Inc. +# 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. + +--- !ruby/object:Api::Product +name: IAMBeta +display_name: Cloud IAM +versions: + - !ruby/object:Api::Product::Version + name: beta + base_url: https://iam.googleapis.com/v1beta/ +scopes: + - https://www.googleapis.com/auth/iam +apis_required: + - !ruby/object:Api::Product::ApiReference + name: Identity and Access Management (IAM) API + url: https://console.cloud.google.com/apis/library/iam.googleapis.com/ +objects: + - !ruby/object:Api::Resource + name: 'WorkloadIdentityPool' + min_version: beta + base_url: projects/{{project}}/locations/global/workloadIdentityPools + create_url: projects/{{project}}/locations/global/workloadIdentityPools?workloadIdentityPoolId={{workload_identity_pool_id}} + description: | + Represents a collection of external workload identities. You can define IAM policies to + grant these identities access to Google Cloud resources. + update_mask: true + properties: + - !ruby/object:Api::Type::String + name: 'workloadIdentityPoolId' + description: | + The ID to use for the pool, which becomes the final component of the resource name. This + value should be 4-32 characters, and may contain the characters [a-z0-9-]. The prefix + `gcp-` is reserved for use by Google, and may not be specified. + required: true + input: true + url_param_only: true + - !ruby/object:Api::Type::Enum + name: 'state' + description: | + The state of the pool. + STATE_UNSPECIFIED: State unspecified. + ACTIVE: The pool is active, and may be used in Google Cloud policies. + DELETED: The pool is soft-deleted. Soft-deleted pools are permanently deleted after + approximately 30 days. You can restore a soft-deleted pool using + UndeleteWorkloadIdentityPool. You cannot reuse the ID of a soft-deleted pool until it is + permanently deleted. While a pool is deleted, you cannot use it to exchange tokens, or + use existing tokens to access resources. If the pool is undeleted, existing tokens grant + access again. + output: true + values: + - :STATE_UNSPECIFIED + - :ACTIVE + - :DELETED + - !ruby/object:Api::Type::String + name: 'displayName' + description: A display name for the pool. Cannot exceed 32 characters. + - !ruby/object:Api::Type::String + name: 'description' + description: A description of the pool. Cannot exceed 256 characters. + - !ruby/object:Api::Type::String + name: 'name' + description: | + The resource name of the pool as + `projects//locations/global/workloadIdentityPools/`. + output: true + - !ruby/object:Api::Type::Boolean + name: 'disabled' + description: | + Whether the pool is disabled. You cannot use a disabled pool to exchange tokens, or use + existing tokens to access resources. If the pool is re-enabled, existing tokens grant + access again. diff --git a/products/iam/terraform.yaml b/products/iambeta/terraform.yaml similarity index 69% rename from products/iam/terraform.yaml rename to products/iambeta/terraform.yaml index 8d2178c73b5f..88485f19bf30 100644 --- a/products/iam/terraform.yaml +++ b/products/iambeta/terraform.yaml @@ -12,15 +12,7 @@ # limitations under the License. --- !ruby/object:Provider::Terraform::Config -overrides: !ruby/object:Overrides::ResourceOverrides - Role: !ruby/object:Overrides::Terraform::ResourceOverride - exclude: true - ServiceAccount: !ruby/object:Overrides::Terraform::ResourceOverride - exclude: true - ServiceAccountKey: !ruby/object:Overrides::Terraform::ResourceOverride - exclude: true - OrganizationCustomRole: !ruby/object:Overrides::Terraform::ResourceOverride - exclude: true +legacy_name: iam # This is for copying files over files: !ruby/object:Provider::Config::Files # These files have templating (ERB) code that will be run. diff --git a/third_party/terraform/tests/resource_iam_workload_identity_pool_test.go b/third_party/terraform/tests/resource_iam_beta_workload_identity_pool_test.go.erb similarity index 70% rename from third_party/terraform/tests/resource_iam_workload_identity_pool_test.go rename to third_party/terraform/tests/resource_iam_beta_workload_identity_pool_test.go.erb index 3983c5697036..50a4fdf54cbd 100644 --- a/third_party/terraform/tests/resource_iam_workload_identity_pool_test.go +++ b/third_party/terraform/tests/resource_iam_beta_workload_identity_pool_test.go.erb @@ -1,12 +1,14 @@ +<% autogen_exception -%> package google +<% unless version == 'ga' %> import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAccIAMWorkloadIdentityPool_example(t *testing.T) { +func TestAccIAMBetaWorkloadIdentityPool_example(t *testing.T) { t.Parallel() context := map[string]interface{}{ @@ -20,19 +22,13 @@ func TestAccIAMWorkloadIdentityPool_example(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccIAMWorkloadIdentityPool_example(context), - }, - { - ResourceName: "google_iam_workload_identity_pool.my_pool", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"project"}, + Config: testAccIAMBetaWorkloadIdentityPool_example(context), }, }, }) } -func testAccIAMWorkloadIdentityPool_example(context map[string]interface{}) string { +func testAccIAMBetaWorkloadIdentityPool_example(context map[string]interface{}) string { return Nprintf(` resource "google_project" "my_project" { project_id = "tf-test%{random_suffix}" @@ -53,3 +49,4 @@ resource "google_iam_workload_identity_pool" "my_pool" { } `, context) } +<% end -%> diff --git a/third_party/terraform/utils/config.go.erb b/third_party/terraform/utils/config.go.erb index 4d3ba9b5039b..27a21c63f7aa 100644 --- a/third_party/terraform/utils/config.go.erb +++ b/third_party/terraform/utils/config.go.erb @@ -104,6 +104,7 @@ type Config struct { DnsBetaBasePath string IamCredentialsBasePath string ResourceManagerV2Beta1BasePath string + IAMBasePath string CloudIoTBasePath string ServiceNetworkingBasePath string StorageTransferBasePath string @@ -866,6 +867,7 @@ func ConfigureBasePaths(c *Config) { c.DnsBetaBasePath = DnsBetaDefaultBasePath c.IamCredentialsBasePath = IamCredentialsDefaultBasePath c.ResourceManagerV2Beta1BasePath = ResourceManagerV2Beta1DefaultBasePath + c.IAMBasePath = IAMDefaultBasePath c.ServiceNetworkingBasePath = ServiceNetworkingDefaultBasePath c.BigQueryBasePath = BigQueryDefaultBasePath c.StorageTransferBasePath = StorageTransferDefaultBasePath diff --git a/third_party/terraform/utils/provider.go.erb b/third_party/terraform/utils/provider.go.erb index 60aae5e9e1cf..32845a074bf3 100644 --- a/third_party/terraform/utils/provider.go.erb +++ b/third_party/terraform/utils/provider.go.erb @@ -158,6 +158,7 @@ func Provider() *schema.Provider { IamCredentialsCustomEndpointEntryKey: IamCredentialsCustomEndpointEntry, ResourceManagerV2Beta1CustomEndpointEntryKey: ResourceManagerV2Beta1CustomEndpointEntry, RuntimeConfigCustomEndpointEntryKey: RuntimeConfigCustomEndpointEntry, + IAMCustomEndpointEntryKey: IAMCustomEndpointEntry, ServiceNetworkingCustomEndpointEntryKey: ServiceNetworkingCustomEndpointEntry, ServiceUsageCustomEndpointEntryKey: ServiceUsageCustomEndpointEntry, StorageTransferCustomEndpointEntryKey: StorageTransferCustomEndpointEntry, @@ -529,6 +530,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.IamCredentialsBasePath = d.Get(IamCredentialsCustomEndpointEntryKey).(string) config.ResourceManagerV2Beta1BasePath = d.Get(ResourceManagerV2Beta1CustomEndpointEntryKey).(string) config.RuntimeConfigBasePath = d.Get(RuntimeConfigCustomEndpointEntryKey).(string) + config.IAMBasePath = d.Get(IAMCustomEndpointEntryKey).(string) config.ServiceNetworkingBasePath = d.Get(ServiceNetworkingCustomEndpointEntryKey).(string) config.ServiceUsageBasePath = d.Get(ServiceUsageCustomEndpointEntryKey).(string) config.StorageTransferBasePath = d.Get(StorageTransferCustomEndpointEntryKey).(string) diff --git a/third_party/terraform/utils/provider_handwritten_endpoint.go.erb b/third_party/terraform/utils/provider_handwritten_endpoint.go.erb index 03b4b263f25c..52a537369a8b 100644 --- a/third_party/terraform/utils/provider_handwritten_endpoint.go.erb +++ b/third_party/terraform/utils/provider_handwritten_endpoint.go.erb @@ -104,6 +104,17 @@ var DnsBetaCustomEndpointEntry = &schema.Schema{ }, DnsBetaDefaultBasePath), } +var IAMDefaultBasePath = "https://iam.googleapis.com/v1/" +var IAMCustomEndpointEntryKey = "iam_custom_endpoint" +var IAMCustomEndpointEntry = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateCustomEndpoint, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_IAM_CUSTOM_ENDPOINT", + }, IAMDefaultBasePath), +} + var IamCredentialsDefaultBasePath = "https://iamcredentials.googleapis.com/v1/" var IamCredentialsCustomEndpointEntryKey = "iam_credentials_custom_endpoint" var IamCredentialsCustomEndpointEntry = &schema.Schema{ diff --git a/third_party/terraform/website/docs/guides/provider_reference.html.markdown b/third_party/terraform/website/docs/guides/provider_reference.html.markdown index 6c52aa542c8b..63cfe899dfa0 100644 --- a/third_party/terraform/website/docs/guides/provider_reference.html.markdown +++ b/third_party/terraform/website/docs/guides/provider_reference.html.markdown @@ -126,9 +126,9 @@ resource project for preconditions, quota, and billing, instead of the project the credentials belong to. Not all resources support this- see the documentation for each resource to learn whether it does. -* `billing_project` - (Optional) This fields specifies a project that's used for -preconditions, quota, and billing for requests. All resources that support user project -overrides will use this project instead of the resource's project (if available). This +* `billing_project` - (Optional) This fields specifies a project that's used for +preconditions, quota, and billing for requests. All resources that support user project +overrides will use this project instead of the resource's project (if available). This field is ignored if `user_project_override` is set to false or unset. * `{{service}}_custom_endpoint` - (Optional) The endpoint for a service's APIs, @@ -211,7 +211,7 @@ following ordered by precedence. --- * `billing_project` - (Optional) This fields allows Terraform to set X-Goog-User-Project -for APIs that require a billing project to be specified like Access Context Manager APIs if +for APIs that require a billing project to be specified like Access Context Manager APIs if User ADCs are being used. This can also be specified using the `GOOGLE_BILLING_PROJECT` environment variable. @@ -304,7 +304,7 @@ be used for configuration are below: * `dns_beta_custom_endpoint` (`GOOGLE_DNS_BETA_CUSTOM_ENDPOINT`) - `https://www.googleapis.com/dns/v1beta2/` * `filestore_custom_endpoint` (`GOOGLE_FILESTORE_CUSTOM_ENDPOINT`) - `https://file.googleapis.com/v1/` * `firestore_custom_endpoint` (`GOOGLE_FIRESTORE_CUSTOM_ENDPOINT`) - `https://firestore.googleapis.com/v1/` -* `iam_custom_endpoint` (`GOOGLE_IAM_CUSTOM_ENDPOINT`) - `https://iam.googleapis.com/v1/` | `https://iam.googleapis.com/v1beta/` +* `iam_custom_endpoint` (`GOOGLE_IAM_CUSTOM_ENDPOINT`) - `https://iam.googleapis.com/v1/` * `iam_credentials_custom_endpoint` (`GOOGLE_IAM_CREDENTIALS_CUSTOM_ENDPOINT`) - `https://iamcredentials.googleapis.com/v1/` * `kms_custom_endpoint` (`GOOGLE_KMS_CUSTOM_ENDPOINT`) - `https://cloudkms.googleapis.com/v1/` * `logging_custom_endpoint` (`GOOGLE_LOGGING_CUSTOM_ENDPOINT`) - `https://logging.googleapis.com/v2/` @@ -351,12 +351,12 @@ as their versioned counterpart but that won't necessarily always be the case. * `batching` - (Optional) Controls batching for specific GCP request types where users have encountered quota or speed issues using `count` with - resources that affect the same GCP resource (e.g. `google_project_service`). + resources that affect the same GCP resource (e.g. `google_project_service`). It is not used for every resource/request type and can only group parallel similar calls for nodes at a similar traversal time in the graph during `terraform apply` (e.g. resources created using `count` that affect a single - `project`). Thus, it is also bounded by the `terraform` - [`-parallelism`](https://www.terraform.io/docs/commands/apply.html#parallelism-n) + `project`). Thus, it is also bounded by the `terraform` + [`-parallelism`](https://www.terraform.io/docs/commands/apply.html#parallelism-n) flag, as reducing the number of parallel calls will reduce the number of simultaneous requests being added to a batcher. From 9e09387a67dc484652c0bd3c1f7351666a263aaa Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 16 Oct 2020 09:41:36 +0200 Subject: [PATCH 10/11] copyright 2020 --- products/iambeta/api.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/products/iambeta/api.yaml b/products/iambeta/api.yaml index 3c8a4cdd82e9..887e3696af46 100644 --- a/products/iambeta/api.yaml +++ b/products/iambeta/api.yaml @@ -1,4 +1,4 @@ -# Copyright 2017 Google Inc. +# Copyright 2020 Google Inc. # 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 From 1754b9a2910ffc93a8653e258fba18e4f1dea5bc Mon Sep 17 00:00:00 2001 From: Wilfred Date: Fri, 16 Oct 2020 17:53:21 +0200 Subject: [PATCH 11/11] add tests and async operations --- products/iambeta/api.yaml | 25 +++++- products/iambeta/terraform.yaml | 26 ++++++ .../iam_workload_identity_pool.go.erb | 27 ++++++ .../iam_workload_identity_pool_basic.tf.erb | 4 + .../iam_workload_identity_pool_full.tf.erb | 7 ++ ...beta-workload_identity_pool_id_test.go.erb | 34 +++++++ ...am_beta_workload_identity_pool_test.go.erb | 89 ++++++++++++++----- 7 files changed, 190 insertions(+), 22 deletions(-) create mode 100644 templates/terraform/constants/iam_workload_identity_pool.go.erb create mode 100644 templates/terraform/examples/iam_workload_identity_pool_basic.tf.erb create mode 100644 templates/terraform/examples/iam_workload_identity_pool_full.tf.erb create mode 100644 third_party/terraform/tests/resource_iam_beta-workload_identity_pool_id_test.go.erb diff --git a/products/iambeta/api.yaml b/products/iambeta/api.yaml index 887e3696af46..8a9ed3ffec37 100644 --- a/products/iambeta/api.yaml +++ b/products/iambeta/api.yaml @@ -24,16 +24,39 @@ apis_required: - !ruby/object:Api::Product::ApiReference name: Identity and Access Management (IAM) API url: https://console.cloud.google.com/apis/library/iam.googleapis.com/ +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: 'name' + base_url: '{{op_id}}' + wait_ms: 1000 + result: !ruby/object:Api::OpAsync::Result + path: 'targetLink' + status: !ruby/object:Api::OpAsync::Status + path: 'done' + complete: True + allowed: + - true + - false + error: !ruby/object:Api::OpAsync::Error + path: 'error' + message: 'message' objects: - !ruby/object:Api::Resource name: 'WorkloadIdentityPool' min_version: beta base_url: projects/{{project}}/locations/global/workloadIdentityPools + self_link: projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}} create_url: projects/{{project}}/locations/global/workloadIdentityPools?workloadIdentityPoolId={{workload_identity_pool_id}} + update_verb: :PATCH + update_mask: true description: | Represents a collection of external workload identities. You can define IAM policies to grant these identities access to Google Cloud resources. - update_mask: true + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Managing workload identity pools': + 'https://cloud.google.com/iam/docs/manage-workload-identity-pools-providers#pools' + api: 'https://cloud.google.com/iam/docs/reference/rest/v1beta/projects.locations.workloadIdentityPools' properties: - !ruby/object:Api::Type::String name: 'workloadIdentityPoolId' diff --git a/products/iambeta/terraform.yaml b/products/iambeta/terraform.yaml index 88485f19bf30..d0a01a2f3ae0 100644 --- a/products/iambeta/terraform.yaml +++ b/products/iambeta/terraform.yaml @@ -13,6 +13,32 @@ --- !ruby/object:Provider::Terraform::Config legacy_name: iam +overrides: !ruby/object:Overrides::ResourceOverrides + WorkloadIdentityPool: !ruby/object:Overrides::Terraform::ResourceOverride + autogen_async: true + import_format: ["projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}}"] + examples: + - !ruby/object:Provider::Terraform::Examples + name: "iam_workload_identity_pool_basic" + primary_resource_id: "example" + vars: + workload_identity_pool_id: "example-pool" + min_version: beta + - !ruby/object:Provider::Terraform::Examples + name: "iam_workload_identity_pool_full" + primary_resource_id: "example" + vars: + workload_identity_pool_id: "example-pool" + min_version: beta + docs: !ruby/object:Provider::Terraform::Docs + attributes: | + * `self_link`: The self link of the created WorkloadIdentityPool in the format `projects/{project}/locations/global/workloadIdentityPools/{workload_identity_pool_id}` + custom_code: !ruby/object:Provider::Terraform::CustomCode + constants: templates/terraform/constants/iam_workload_identity_pool.go.erb + properties: + workloadIdentityPoolId: !ruby/object:Overrides::Terraform::PropertyOverride + validation: !ruby/object:Provider::Terraform::Validation + function: 'validateWorkloadIdentityPoolId' # This is for copying files over files: !ruby/object:Provider::Config::Files # These files have templating (ERB) code that will be run. diff --git a/templates/terraform/constants/iam_workload_identity_pool.go.erb b/templates/terraform/constants/iam_workload_identity_pool.go.erb new file mode 100644 index 000000000000..76d72b10a9f5 --- /dev/null +++ b/templates/terraform/constants/iam_workload_identity_pool.go.erb @@ -0,0 +1,27 @@ +const workloadIdentityPoolIdRegexp = `^[0-9a-z-]+$` + +func validateWorkloadIdentityPoolId(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + + if strings.HasPrefix(value, "gcp-") { + errors = append(errors, fmt.Errorf( + "%q (%q) can not start with \"gcp-\"", k, value)) + } + + if !regexp.MustCompile(workloadIdentityPoolIdRegexp).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q must contain only lowercase letters (a-z), numbers (0-9), or dashes (-)", k)) + } + + if len(value) < 4 { + errors = append(errors, fmt.Errorf( + "%q cannot be smaller than 4 characters", k)) + } + + if len(value) > 32 { + errors = append(errors, fmt.Errorf( + "%q cannot be greater than 32 characters", k)) + } + + return +} diff --git a/templates/terraform/examples/iam_workload_identity_pool_basic.tf.erb b/templates/terraform/examples/iam_workload_identity_pool_basic.tf.erb new file mode 100644 index 000000000000..1efbcabd8ff3 --- /dev/null +++ b/templates/terraform/examples/iam_workload_identity_pool_basic.tf.erb @@ -0,0 +1,4 @@ +resource "google_iam_workload_identity_pool" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + workload_identity_pool_id = "<%= ctx[:vars]["workload_identity_pool_id"] %>" +} diff --git a/templates/terraform/examples/iam_workload_identity_pool_full.tf.erb b/templates/terraform/examples/iam_workload_identity_pool_full.tf.erb new file mode 100644 index 000000000000..e1060ce23ff0 --- /dev/null +++ b/templates/terraform/examples/iam_workload_identity_pool_full.tf.erb @@ -0,0 +1,7 @@ +resource "google_iam_workload_identity_pool" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + workload_identity_pool_id = "<%= ctx[:vars]["workload_identity_pool_id"] %>" + display_name = "Name of pool" + description = "Identity pool for automated test" + disabled = true +} diff --git a/third_party/terraform/tests/resource_iam_beta-workload_identity_pool_id_test.go.erb b/third_party/terraform/tests/resource_iam_beta-workload_identity_pool_id_test.go.erb new file mode 100644 index 000000000000..52e7b52c73b0 --- /dev/null +++ b/third_party/terraform/tests/resource_iam_beta-workload_identity_pool_id_test.go.erb @@ -0,0 +1,34 @@ +<% autogen_exception -%> +package google + +<% unless version == 'ga' %> +import ( + "strings" + "testing" +) + +func TestValidateIAMBetaWorkloadIdentityPoolId(t *testing.T) { + x := []StringValidationTestCase{ + // No errors + {TestName: "basic", Value: "foobar"}, + {TestName: "with numbers", Value: "foobar123"}, + {TestName: "short", Value: "foos"}, + {TestName: "long", Value: "12345678901234567890123456789012"}, + {TestName: "has a hyphen", Value: "foo-bar"}, + + // With errors + {TestName: "empty", Value: "", ExpectError: true}, + {TestName: "starts with a gcp-", Value: "gcp-foobar", ExpectError: true}, + {TestName: "with uppercase", Value: "fooBar", ExpectError: true}, + {TestName: "has an slash", Value: "foo/bar", ExpectError: true}, + {TestName: "has an backslash", Value: "foo\bar", ExpectError: true}, + {TestName: "too short", Value: "foo", ExpectError: true}, + {TestName: "too long", Value: strings.Repeat("f", 33), ExpectError: true}, + } + + es := testStringValidationCases(x, validateWorkloadIdentityPoolId) + if len(es) > 0 { + t.Errorf("Failed to validate WorkloadIdentityPool names: %v", es) + } +} +<% end -%> diff --git a/third_party/terraform/tests/resource_iam_beta_workload_identity_pool_test.go.erb b/third_party/terraform/tests/resource_iam_beta_workload_identity_pool_test.go.erb index 50a4fdf54cbd..a5458976aa90 100644 --- a/third_party/terraform/tests/resource_iam_beta_workload_identity_pool_test.go.erb +++ b/third_party/terraform/tests/resource_iam_beta_workload_identity_pool_test.go.erb @@ -3,50 +3,97 @@ package google <% unless version == 'ga' %> import ( + "fmt" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAccIAMBetaWorkloadIdentityPool_example(t *testing.T) { +func TestAccIAMBetaWorkloadIdentityPool_full(t *testing.T) { t.Parallel() - context := map[string]interface{}{ - "org_id": getTestOrgFromEnv(t), - "org_domain": getTestOrgDomainFromEnv(t), - "random_suffix": randString(t, 10), - } + randomSuffix := randString(t, 10) vcrTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccIAMBetaWorkloadIdentityPool_example(context), + Config: testAccIAMBetaWorkloadIdentityPool_full(randomSuffix), + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMBetaWorkloadIdentityPool_update(randomSuffix), + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, }, }, }) } -func testAccIAMBetaWorkloadIdentityPool_example(context map[string]interface{}) string { - return Nprintf(` -resource "google_project" "my_project" { - project_id = "tf-test%{random_suffix}" - name = "tf-test%{random_suffix}" - org_id = "%{org_id}" +func TestAccIAMBetaWorkloadIdentityPool_minimal(t *testing.T) { + t.Parallel() + + randomSuffix := randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPool_minimal(randomSuffix), + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMBetaWorkloadIdentityPool_update(randomSuffix), + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) } -resource "google_project_service" "my_service" { - project = google_project.my_project.project_id - service = "iam.googleapis.com" +func testAccIAMBetaWorkloadIdentityPool_full(suffix string) string { + return fmt.Sprintf(` +resource "google_iam_workload_identity_pool" "my_pool" { + workload_identity_pool_id = "my-pool-%s" + display_name = "Name of pool" + description = "Identity pool for automated test" + disabled = true +} +`, suffix) +} + +func testAccIAMBetaWorkloadIdentityPool_minimal(suffix string) string { + return fmt.Sprintf(` +resource "google_iam_workload_identity_pool" "my_pool" { + workload_identity_pool_id = "my-pool-%s" +} +`, suffix) } +func testAccIAMBetaWorkloadIdentityPool_update(suffix string) string { + return fmt.Sprintf(` resource "google_iam_workload_identity_pool" "my_pool" { - project = google_project_service.my_service.project - display_name = "Name of pool" - description = "Identity pool for automated test" - disabled = true + workload_identity_pool_id = "my-pool-%s" + display_name = "Updated name of pool" + description = "Updated description" + disabled = false } -`, context) +`, suffix) } <% end -%>