Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ACM policies fine grained resources #8038

Merged
merged 10 commits into from
Jun 5, 2023
1 change: 1 addition & 0 deletions mmv1/products/accesscontextmanager/EgressPolicy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# This resource has been deprecated, please refer to ServicePerimeterEgressPolicy.
Copy link
Member

@c2thorn c2thorn Jun 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, I should have been more specific. I think we should replace the description of these resources with a warning that it has been deprecated, and tell the user to go to the google_access_context_manager_service_perimeter_*_policy equivalent. My intention is that the registry documentation gets changed so that any users wanting to lookup the ingress/egress policy TF documentation get redirected to the correct ones.

Copy link
Member

@c2thorn c2thorn Jun 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, better yet, let's skip the docs entirely for these resources. Using skip_docs: true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like skip_docs is an attribute for skipping the examples. Do we have another attribute for skipping docs entirely? Otherwise I can change in the description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I confused that one then. It looks like we do not have an attribute. Changing the description is fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, updated

--- !ruby/object:Api::Resource
name: 'EgressPolicy'
create_url: '{{egress_policy_name}}'
Expand Down
1 change: 1 addition & 0 deletions mmv1/products/accesscontextmanager/IngressPolicy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# This resource has been deprecated, please refer to ServicePerimeterIngressPolicy.
--- !ruby/object:Api::Resource
name: 'IngressPolicy'
create_url: '{{ingress_policy_name}}'
Expand Down
136 changes: 136 additions & 0 deletions mmv1/products/accesscontextmanager/ServicePerimeterEgressPolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Copyright 2018 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::Resource
name: 'ServicePerimeterEgressPolicy'
create_url: '{{perimeter}}'
base_url: ''
self_link: '{{perimeter}}'
create_verb: :PATCH
delete_verb: :PATCH
update_mask: true
identity:
- egressFrom
- egressTo
nested_query: !ruby/object:Api::Resource::NestedQuery
modify_by_patch: true
is_list_of_ids: false
keys:
- status
- egressPolicies
references: !ruby/object:Api::Resource::ReferenceLinks
api: 'https://cloud.google.com/access-context-manager/docs/reference/rest/v1/accessPolicies.servicePerimeters#egresspolicy'
description: |
EgressPolicies match requests based on egressFrom and egressTo stanzas.
For an EgressPolicy to match, both egressFrom and egressTo stanzas must be matched.
If an EgressPolicy matches a request, the request is allowed to span the ServicePerimeter
boundary. For example, an EgressPolicy can be used to allow VMs on networks
within the ServicePerimeter to access a defined set of projects outside the
perimeter in certain contexts (e.g. to read data from a Cloud Storage bucket
or query against a BigQuery dataset).
autogen_async: true
exclude_validator: true
# Skipping the sweeper due to the non-standard base_url and because this is fine-grained under ServicePerimeter
skip_sweeper: true
id_format: '{{perimeter}}'
import_format: ['{{perimeter}}']
mutex: '{{perimeter}}'
custom_code: !ruby/object:Provider::Terraform::CustomCode
custom_import: templates/terraform/custom_import/access_context_manager_service_perimeter_ingress_policy.go.erb
parameters:
- !ruby/object:Api::Type::ResourceRef
name: 'perimeter'
resource: 'ServicePerimeter'
imports: 'name'
description: |
The name of the Service Perimeter to add this resource to.
required: true
immutable: true
url_param_only: true
properties:
- !ruby/object:Api::Type::NestedObject
name: 'egressFrom'
description: |
Defines conditions on the source of a request causing this `EgressPolicy` to apply.
properties:
- !ruby/object:Api::Type::Enum
name: 'identityType'
description: |
Specifies the type of identities that are allowed access to outside the
perimeter. If left unspecified, then members of `identities` field will
be allowed access.
values:
- :ANY_IDENTITY
- :ANY_USER_ACCOUNT
- :ANY_SERVICE_ACCOUNT
- !ruby/object:Api::Type::Array
name: 'identities'
description: |
A list of identities that are allowed access through this `EgressPolicy`.
Should be in the format of email address. The email address should
represent individual user or service account only.
item_type: Api::Type::String
- !ruby/object:Api::Type::NestedObject
name: 'egressTo'
description: |
Defines the conditions on the `ApiOperation` and destination resources that
cause this `EgressPolicy` to apply.
properties:
- !ruby/object:Api::Type::Array
name: 'resources'
item_type: Api::Type::String
description: |
A list of resources, currently only projects in the form
`projects/<projectnumber>`, that match this to stanza. A request matches
if it contains a resource in this list. If * is specified for resources,
then this `EgressTo` rule will authorize access to all resources outside
the perimeter.
- !ruby/object:Api::Type::Array
name: 'externalResources'
item_type: Api::Type::String
description: |
A list of external resources that are allowed to be accessed. A request
matches if it contains an external resource in this list (Example:
s3://bucket/path). Currently '*' is not allowed.
- !ruby/object:Api::Type::Array
name: 'operations'
description: |
A list of `ApiOperations` that this egress rule applies to. A request matches
if it contains an operation/service in this list.
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
name: 'serviceName'
description: |
The name of the API whose methods or permissions the `IngressPolicy` or
`EgressPolicy` want to allow. A single `ApiOperation` with serviceName
field set to `*` will allow all methods AND permissions for all services.
- !ruby/object:Api::Type::Array
name: 'methodSelectors'
description: |
API methods or permissions to allow. Method or permission must belong
to the service specified by `serviceName` field. A single MethodSelector
entry with `*` specified for the `method` field will allow all methods
AND permissions for the service specified in `serviceName`.
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
name: 'method'
description: |
Value for `method` should be a valid method name for the corresponding
`serviceName` in `ApiOperation`. If `*` used as value for method,
then ALL methods and permissions are allowed.
- !ruby/object:Api::Type::String
name: 'permission'
description: |
Value for permission should be a valid Cloud IAM permission for the
corresponding `serviceName` in `ApiOperation`.
160 changes: 160 additions & 0 deletions mmv1/products/accesscontextmanager/ServicePerimeterIngressPolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Copyright 2018 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::Resource
name: 'ServicePerimeterIngressPolicy'
create_url: '{{perimeter}}'
base_url: ''
self_link: '{{perimeter}}'
create_verb: :PATCH
delete_verb: :PATCH
update_mask: true
identity:
- ingressFrom
- ingressTo
nested_query: !ruby/object:Api::Resource::NestedQuery
modify_by_patch: true
is_list_of_ids: false
keys:
- status
- ingressPolicies
references: !ruby/object:Api::Resource::ReferenceLinks
api: 'https://cloud.google.com/access-context-manager/docs/reference/rest/v1/accessPolicies.servicePerimeters#ingresspolicy'
description: |
IngressPolicies match requests based on ingressFrom and ingressTo stanzas. For an ingress policy to match,
both the ingressFrom and ingressTo stanzas must be matched. If an IngressPolicy matches a request,
the request is allowed through the perimeter boundary from outside the perimeter.
For example, access from the internet can be allowed either based on an AccessLevel or,
for traffic hosted on Google Cloud, the project of the source network.
For access from private networks, using the project of the hosting network is required.
Individual ingress policies can be limited by restricting which services and/
or actions they match using the ingressTo field.
autogen_async: true
exclude_validator: true
# Skipping the sweeper due to the non-standard base_url and because this is fine-grained under ServicePerimeter
skip_sweeper: true
id_format: '{{perimeter}}'
import_format: ['{{perimeter}}']
mutex: '{{perimeter}}'
custom_code: !ruby/object:Provider::Terraform::CustomCode
custom_import: templates/terraform/custom_import/access_context_manager_service_perimeter_ingress_policy.go.erb
parameters:
- !ruby/object:Api::Type::ResourceRef
name: 'perimeter'
resource: 'ServicePerimeter'
imports: 'name'
description: |
The name of the Service Perimeter to add this resource to.
required: true
immutable: true
url_param_only: true
properties:
- !ruby/object:Api::Type::NestedObject
name: 'ingressFrom'
description: |
Defines the conditions on the source of a request causing this `IngressPolicy`
to apply.
properties:
- !ruby/object:Api::Type::Enum
name: 'identityType'
description: |
Specifies the type of identities that are allowed access from outside the
perimeter. If left unspecified, then members of `identities` field will be
allowed access.
values:
- :ANY_IDENTITY
- :ANY_USER_ACCOUNT
- :ANY_SERVICE_ACCOUNT
- !ruby/object:Api::Type::Array
name: 'identities'
item_type: Api::Type::String
description: |
A list of identities that are allowed access through this ingress policy.
Should be in the format of email address. The email address should represent
individual user or service account only.
- !ruby/object:Api::Type::Array
name: 'sources'
description: |
Sources that this `IngressPolicy` authorizes access from.
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
name: 'accessLevel'
description: |
An `AccessLevel` resource name that allow resources within the
`ServicePerimeters` to be accessed from the internet. `AccessLevels` listed
must be in the same policy as this `ServicePerimeter`. Referencing a nonexistent
`AccessLevel` will cause an error. If no `AccessLevel` names are listed,
resources within the perimeter can only be accessed via Google Cloud calls
with request origins within the perimeter.
Example `accessPolicies/MY_POLICY/accessLevels/MY_LEVEL.`
If * is specified, then all IngressSources will be allowed.
- !ruby/object:Api::Type::String
name: 'resource'
description: |
A Google Cloud resource that is allowed to ingress the perimeter.
Requests from these resources will be allowed to access perimeter data.
Currently only projects are allowed. Format `projects/{project_number}`
The project may be in any Google Cloud organization, not just the
organization that the perimeter is defined in. `*` is not allowed, the case
of allowing all Google Cloud resources only is not supported.
- !ruby/object:Api::Type::NestedObject
name: 'ingressTo'
description: |
Defines the conditions on the `ApiOperation` and request destination that cause
this `IngressPolicy` to apply.
properties:
- !ruby/object:Api::Type::Array
name: 'resources'
item_type: Api::Type::String
description: |
A list of resources, currently only projects in the form
`projects/<projectnumber>`, protected by this `ServicePerimeter`
that are allowed to be accessed by sources defined in the
corresponding `IngressFrom`. A request matches if it contains
a resource in this list. If `*` is specified for resources,
then this `IngressTo` rule will authorize access to all
resources inside the perimeter, provided that the request
also matches the `operations` field.
- !ruby/object:Api::Type::Array
name: 'operations'
description: |
A list of `ApiOperations` the sources specified in corresponding `IngressFrom`
are allowed to perform in this `ServicePerimeter`.
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
name: 'serviceName'
description: |
The name of the API whose methods or permissions the `IngressPolicy` or
`EgressPolicy` want to allow. A single `ApiOperation` with `serviceName`
field set to `*` will allow all methods AND permissions for all services.
- !ruby/object:Api::Type::Array
name: 'methodSelectors'
description: |
API methods or permissions to allow. Method or permission must belong to
the service specified by serviceName field. A single `MethodSelector` entry
with `*` specified for the method field will allow all methods AND
permissions for the service specified in `serviceName`.
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
name: 'method'
description: |
Value for method should be a valid method name for the corresponding
serviceName in `ApiOperation`. If `*` used as value for `method`, then
ALL methods and permissions are allowed.
- !ruby/object:Api::Type::String
name: 'permission'
description: |
Value for permission should be a valid Cloud IAM permission for the
corresponding `serviceName` in `ApiOperation`.
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@
config := meta.(*transport_tpg.Config)

// current import_formats can't import fields with forward slashes in their value
parts, err := tpgresource.GetImportIdQualifiers([]string{"accessPolicies/(?P<accessPolicy>[^/]+)/servicePerimeters/(?P<perimeter>[^/]+)/(?P<resource>.+)"}, d, config, d.Id())
parts, err := tpgresource.GetImportIdQualifiers([]string{"accessPolicies/(?P<accessPolicy>[^/]+)/servicePerimeters/(?P<perimeter>[^/]+)"}, d, config, d.Id())
if err != nil {
return nil, err
}

if err := d.Set("egress_policy_name", fmt.Sprintf("accessPolicies/%s/servicePerimeters/%s", parts["accessPolicy"], parts["perimeter"])); err != nil {
return nil, fmt.Errorf("Error setting egress_policy_name: %s", err)
}
if err := d.Set("resource", parts["resource"]); err != nil {
return nil, fmt.Errorf("Error setting resource: %s", err)
if err := d.Set("perimeter", fmt.Sprintf("accessPolicies/%s/servicePerimeters/%s", parts["accessPolicy"], parts["perimeter"])); err != nil {
return nil, fmt.Errorf("Error setting perimeter: %s", err)
}
return []*schema.ResourceData{d}, nil
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@
config := meta.(*transport_tpg.Config)

// current import_formats can't import fields with forward slashes in their value
parts, err := tpgresource.GetImportIdQualifiers([]string{"accessPolicies/(?P<accessPolicy>[^/]+)/servicePerimeters/(?P<perimeter>[^/]+)/(?P<resource>.+)"}, d, config, d.Id())
parts, err := tpgresource.GetImportIdQualifiers([]string{"accessPolicies/(?P<accessPolicy>[^/]+)/servicePerimeters/(?P<perimeter>[^/]+)"}, d, config, d.Id())
if err != nil {
return nil, err
}

if err := d.Set("ingress_policy_name", fmt.Sprintf("accessPolicies/%s/servicePerimeters/%s", parts["accessPolicy"], parts["perimeter"])); err != nil {
return nil, fmt.Errorf("Error setting ingress_policy_name: %s", err)
}
if err := d.Set("resource", parts["resource"]); err != nil {
return nil, fmt.Errorf("Error setting resource: %s", err)
if err := d.Set("perimeter", fmt.Sprintf("accessPolicies/%s/servicePerimeters/%s", parts["accessPolicy"], parts["perimeter"])); err != nil {
return nil, fmt.Errorf("Error setting perimeter: %s", err)
}
return []*schema.ResourceData{d}, nil
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,21 @@ func testSweepAccessContextManagerPolicies(region string) error {
// can exist, they need to be run serially
func TestAccAccessContextManager(t *testing.T) {
testCases := map[string]func(t *testing.T){
"access_policy": testAccAccessContextManagerAccessPolicy_basicTest,
"access_policy_scoped": testAccAccessContextManagerAccessPolicy_scopedTest,
"service_perimeter": testAccAccessContextManagerServicePerimeter_basicTest,
"service_perimeter_update": testAccAccessContextManagerServicePerimeter_updateTest,
"service_perimeter_resource": testAccAccessContextManagerServicePerimeterResource_basicTest,
"access_level": testAccAccessContextManagerAccessLevel_basicTest,
"access_level_full": testAccAccessContextManagerAccessLevel_fullTest,
"access_level_custom": testAccAccessContextManagerAccessLevel_customTest,
"access_levels": testAccAccessContextManagerAccessLevels_basicTest,
"access_level_condition": testAccAccessContextManagerAccessLevelCondition_basicTest,
"egress_policy": testAccAccessContextManagerEgressPolicy_basicTest,
"ingress_policy": testAccAccessContextManagerIngressPolicy_basicTest,
"service_perimeters": testAccAccessContextManagerServicePerimeters_basicTest,
"gcp_user_access_binding": testAccAccessContextManagerGcpUserAccessBinding_basicTest,
"authorized_orgs_desc": testAccAccessContextManagerAuthorizedOrgsDesc_basicTest,
"access_policy": testAccAccessContextManagerAccessPolicy_basicTest,
"access_policy_scoped": testAccAccessContextManagerAccessPolicy_scopedTest,
"service_perimeter": testAccAccessContextManagerServicePerimeter_basicTest,
"service_perimeter_update": testAccAccessContextManagerServicePerimeter_updateTest,
"service_perimeter_resource": testAccAccessContextManagerServicePerimeterResource_basicTest,
"access_level": testAccAccessContextManagerAccessLevel_basicTest,
"access_level_full": testAccAccessContextManagerAccessLevel_fullTest,
"access_level_custom": testAccAccessContextManagerAccessLevel_customTest,
"access_levels": testAccAccessContextManagerAccessLevels_basicTest,
"access_level_condition": testAccAccessContextManagerAccessLevelCondition_basicTest,
"service_perimeter_egress_policy": testAccAccessContextManagerServicePerimeterEgressPolicy_basicTest,
"service_perimeter_ingress_policy": testAccAccessContextManagerServicePerimeterIngressPolicy_basicTest,
"service_perimeters": testAccAccessContextManagerServicePerimeters_basicTest,
"gcp_user_access_binding": testAccAccessContextManagerGcpUserAccessBinding_basicTest,
"authorized_orgs_desc": testAccAccessContextManagerAuthorizedOrgsDesc_basicTest,
}

for name, tc := range testCases {
Expand Down
Loading