Skip to content

Commit

Permalink
Add trust to ad domain 5731 (#3798)
Browse files Browse the repository at this point in the history
* AD Domain resource added

* fmt issue fixed

* validation regex and input flag added

* Trust resouce attributes added to api.yaml

* ad domain trust resource added

* ad domain trust resource added

* post_create attribute added

* nested_query attribute added - work in progress

* work in progress - peer review

* encoder and decoder added - wip

* custom encoders and decoders added for update and delete resource

* comment removed

* comment added

* comment syntax corrected

* comments added as PR review comments
  • Loading branch information
venkykuberan authored Aug 18, 2020
1 parent 58d5a99 commit b7acb81
Show file tree
Hide file tree
Showing 7 changed files with 359 additions and 25 deletions.
136 changes: 113 additions & 23 deletions products/activedirectory/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,6 @@ versions:
base_url: https://managedidentities.googleapis.com/v1/
scopes:
- https://www.googleapis.com/auth/cloud-platform
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
# It takes about 35-40 mins to get the resource created
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 60
update_minutes: 60
delete_minutes: 60
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'
objects:
- !ruby/object:Api::Resource
name: 'Domain'
Expand All @@ -55,6 +33,28 @@ objects:
guides:
'Managed Microsoft Active Directory Quickstart': 'https://cloud.google.com/managed-microsoft-ad/docs/quickstarts'
api: 'https://cloud.google.com/managed-microsoft-ad/reference/rest/v1/projects.locations.global.domains'
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
# It takes about 35-40 mins to get the resource created
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 60
update_minutes: 60
delete_minutes: 60
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'
parameters:
- !ruby/object:Api::Type::String
name: domainName
Expand Down Expand Up @@ -104,4 +104,94 @@ objects:
output: true
description: |
The fully-qualified domain name of the exposed domain used by clients to connect to the service.
Similar to what would be chosen for an Active Directory set up on an internal network.
Similar to what would be chosen for an Active Directory set up on an internal network.
- !ruby/object:Api::Resource
name: 'DomainTrust'
kind: 'activedirectory#trust'
base_url: projects/{{project}}/locations/global/domains
create_url: projects/{{project}}/locations/global/domains/{{domain}}:attachTrust
update_verb: :POST
update_url: projects/{{project}}/locations/global/domains/{{domain}}:reconfigureTrust
delete_verb: :POST
# Resource custom delete function needs to be modified any time when the resource schema is edited
delete_url: projects/{{project}}/locations/global/domains/{{domain}}:detachTrust
self_link: projects/{{project}}/locations/global/domains/{{domain}}
description: Adds a trust between Active Directory domains
identity:
- targetDomainName
nested_query: !ruby/object:Api::Resource::NestedQuery
kind: 'domain#trustList'
keys: ['trusts']
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 10
update_minutes: 10
delete_minutes: 10
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'
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Active Directory Trust': 'https://cloud.google.com/managed-microsoft-ad/docs/create-one-way-trust'
api: 'https://cloud.google.com/managed-microsoft-ad/reference/rest/v1/projects.locations.global.domains/attachTrust'
parameters:
- !ruby/object:Api::Type::String
name: domain
required: true
url_param_only: true
input: true
description: |
The fully qualified domain name. e.g. mydomain.myorganization.com, with the restrictions,
https://cloud.google.com/managed-microsoft-ad/reference/rest/v1/projects.locations.global.domains.
properties:
- !ruby/object:Api::Type::String
name: 'targetDomainName'
required: true
description: 'The fully qualified target domain name which will be in trust with the current domain.'
- !ruby/object:Api::Type::Enum
name: 'trustType'
required: true
input: true
description: 'The type of trust represented by the trust resource.'
values:
- FOREST
- EXTERNAL
- !ruby/object:Api::Type::Enum
name: 'trustDirection'
required: true
input: true
description: 'The trust direction, which decides if the current domain is trusted, trusting, or both.'
values:
- INBOUND
- OUTBOUND
- BIDIRECTIONAL
- !ruby/object:Api::Type::Boolean
name: 'selectiveAuthentication'
input: true
description: |
Whether the trusted side has forest/domain wide access or selective access to an approved set of resources.
- !ruby/object:Api::Type::Array
name: 'targetDnsIpAddresses'
required: true
item_type: Api::Type::String
description: |
The target DNS server IP addresses which can resolve the remote domain involved in the trust.
- !ruby/object:Api::Type::String
name: 'trustHandshakeSecret'
required: true
input: true
description: |
The trust secret used for the handshake with the target domain. This will not be stored.
27 changes: 25 additions & 2 deletions products/activedirectory/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,32 @@ overrides: !ruby/object:Overrides::ResourceOverrides
primary_resource_id: "ad-domain"
vars:
name: "myorg"
domain_name: mydomain
DomainTrust: !ruby/object:Overrides::Terraform::ResourceOverride
id_format: "projects/{{project}}/locations/global/domains/{{domain}}/{{target_domain_name}}"
import_format: ["projects/{{project}}/locations/global/domains/{{domain}}/{{target_domain_name}}"]
autogen_async: true
properties:
targetDnsIpAddresses: !ruby/object:Overrides::Terraform::PropertyOverride
is_set: true
trustHandshakeSecret: !ruby/object:Overrides::Terraform::PropertyOverride
sensitive: true
ignore_read: true
custom_code: !ruby/object:Provider::Terraform::CustomCode
update_encoder: templates/terraform/update_encoder/active_directory_domain_trust.go.erb
# Delete function needs to be modified any time when the resource schema is edited
custom_delete: templates/terraform/custom_delete/active_directory_domain_trust.go.erb
encoder: templates/terraform/encoders/active_directory_domain_trust.go.erb
decoder: templates/terraform/decoders/unwrap_resource.go.erb
examples:
- !ruby/object:Provider::Terraform::Examples
name: "active_directory_domain_trust_basic"
primary_resource_id: "ad-domain-trust"
# Fine-grained resource need different autogenerated tests, as
# we need to check destroy during a test step where the parent resource
# still exists and we need to validate that child resource has been deleted
skip_test: true
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)) -%>
<%= lines(indent(compile('provider/terraform/product~compile.yaml'), 4)) -%>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

url, err := replaceVars(d, config, "{{ActiveDirectoryBasePath}}projects/{{project}}/locations/global/domains/{{domain}}:detachTrust")
if err != nil {
return err
}

<%# The generate DELETE method isn't including the {trust: } object in the response body thus custom_delete is needed -%>

obj := make(map[string]interface{})
targetDomainNameProp, err := expandNestedActiveDirectoryDomainTrustTargetDomainName(d.Get("target_domain_name"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("target_domain_name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, targetDomainNameProp)) {
obj["targetDomainName"] = targetDomainNameProp
}
trustTypeProp, err := expandNestedActiveDirectoryDomainTrustTrustType(d.Get("trust_type"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("trust_type"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, trustTypeProp)) {
obj["trustType"] = trustTypeProp
}
trustDirectionProp, err := expandNestedActiveDirectoryDomainTrustTrustDirection(d.Get("trust_direction"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("trust_direction"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, trustDirectionProp)) {
obj["trustDirection"] = trustDirectionProp
}
selectiveAuthenticationProp, err := expandNestedActiveDirectoryDomainTrustSelectiveAuthentication(d.Get("selective_authentication"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("selective_authentication"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, selectiveAuthenticationProp)) {
obj["selectiveAuthentication"] = selectiveAuthenticationProp
}
targetDnsIpAddressesProp, err := expandNestedActiveDirectoryDomainTrustTargetDnsIpAddresses(d.Get("target_dns_ip_addresses"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("target_dns_ip_addresses"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, targetDnsIpAddressesProp)) {
obj["targetDnsIpAddresses"] = targetDnsIpAddressesProp
}
trustHandshakeSecretProp, err := expandNestedActiveDirectoryDomainTrustTrustHandshakeSecret(d.Get("trust_handshake_secret"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("trust_handshake_secret"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, trustHandshakeSecretProp)) {
obj["trustHandshakeSecret"] = trustHandshakeSecretProp
}

obj, err = resourceActiveDirectoryDomainTrustEncoder(d, meta, obj)
if err != nil {
return err
}

log.Printf("[DEBUG] Deleting DomainTrust %q", d.Id())

res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutDelete))
if err != nil {
return handleNotFoundError(err, d, "DomainTrust")
}

err = activeDirectoryOperationWaitTime(
config, res, project, "Deleting DomainTrust",
d.Timeout(schema.TimeoutDelete))

if err != nil {
return err
}

log.Printf("[DEBUG] Finished deleting DomainTrust %q: %#v", d.Id(), res)
return nil
19 changes: 19 additions & 0 deletions templates/terraform/encoders/active_directory_domain_trust.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<%# The license inside this block applies to this file.
# 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.
-%>

wrappedReq := map[string]interface{}{
"trust": obj,
}
return wrappedReq, nil
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resource "google_active_directory_domain_trust" "ad-domain-trust" {
domain = "test-managed-ad.com"
target_domain_name = "example-gcp.com"
target_dns_ip_addresses = ["10.1.0.100"]
trust_direction = "OUTBOUND"
trust_type = "FOREST"
trust_handshake_secret = "Testing1!"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<%# The license inside this block applies to this file.
# 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.
-%>
wrappedReq := map[string]interface{}{
"targetDomainName": obj["targetDomainName"],
"targetDnsIpAddresses": obj["targetDnsIpAddresses"],
}
return wrappedReq, nil
Loading

0 comments on commit b7acb81

Please sign in to comment.