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 trust to ad domain 5731 #3798

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
venkykuberan marked this conversation as resolved.
Show resolved Hide resolved

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