-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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 support for custom IPsec/IKE policies for VPN connections #834
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,13 +79,19 @@ func resourceArmVirtualNetworkGatewayConnection() *schema.Resource { | |
"enable_bgp": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Default: false, | ||
Computed: true, | ||
}, | ||
|
||
"use_policy_based_traffic_selectors": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Computed: true, | ||
}, | ||
|
||
"routing_weight": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 10, | ||
Computed: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this same default returned from Azure? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same reasoning as above, 10 is the default value, but it should not be fixed in the provider. |
||
}, | ||
|
||
"shared_key": { | ||
|
@@ -94,6 +100,109 @@ func resourceArmVirtualNetworkGatewayConnection() *schema.Resource { | |
Sensitive: true, | ||
}, | ||
|
||
"ipsec_policy": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
MaxItems: 1, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"dh_group": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: ignoreCaseDiffSuppressFunc, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
string(network.DHGroup1), | ||
string(network.DHGroup14), | ||
string(network.DHGroup2), | ||
string(network.DHGroup2048), | ||
string(network.DHGroup24), | ||
string(network.ECP256), | ||
string(network.ECP384), | ||
string(network.None), | ||
}, true), | ||
}, | ||
"ike_encryption": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: ignoreCaseDiffSuppressFunc, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
string(network.AES128), | ||
string(network.AES192), | ||
string(network.AES256), | ||
string(network.DES), | ||
string(network.DES3), | ||
}, true), | ||
}, | ||
"ike_integrity": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: ignoreCaseDiffSuppressFunc, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
string(network.MD5), | ||
string(network.SHA1), | ||
string(network.SHA256), | ||
string(network.SHA384), | ||
}, true), | ||
}, | ||
"ipsec_encryption": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: ignoreCaseDiffSuppressFunc, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
string(network.IpsecEncryptionAES128), | ||
string(network.IpsecEncryptionAES192), | ||
string(network.IpsecEncryptionAES256), | ||
string(network.IpsecEncryptionDES), | ||
string(network.IpsecEncryptionDES3), | ||
string(network.IpsecEncryptionGCMAES128), | ||
string(network.IpsecEncryptionGCMAES192), | ||
string(network.IpsecEncryptionGCMAES256), | ||
string(network.IpsecEncryptionNone), | ||
}, true), | ||
}, | ||
"ipsec_integrity": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: ignoreCaseDiffSuppressFunc, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
string(network.IpsecIntegrityGCMAES128), | ||
string(network.IpsecIntegrityGCMAES192), | ||
string(network.IpsecIntegrityGCMAES256), | ||
string(network.IpsecIntegrityMD5), | ||
string(network.IpsecIntegritySHA1), | ||
string(network.IpsecIntegritySHA256), | ||
}, true), | ||
}, | ||
"pfs_group": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: ignoreCaseDiffSuppressFunc, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
string(network.PfsGroupECP256), | ||
string(network.PfsGroupECP384), | ||
string(network.PfsGroupNone), | ||
string(network.PfsGroupPFS1), | ||
string(network.PfsGroupPFS2), | ||
string(network.PfsGroupPFS2048), | ||
string(network.PfsGroupPFS24), | ||
}, true), | ||
}, | ||
"sa_datasize": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Computed: true, | ||
ValidateFunc: validation.IntAtLeast(1024), | ||
}, | ||
"sa_lifetime": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Computed: true, | ||
ValidateFunc: validation.IntAtLeast(300), | ||
}, | ||
}, | ||
}, | ||
}, | ||
|
||
"tags": tagsSchema(), | ||
}, | ||
} | ||
|
@@ -180,7 +289,9 @@ func resourceArmVirtualNetworkGatewayConnectionRead(d *schema.ResourceData, meta | |
d.Set("virtual_network_gateway_id", conn.VirtualNetworkGateway1.ID) | ||
} | ||
|
||
d.Set("authorization_key", conn.AuthorizationKey) | ||
if conn.AuthorizationKey != nil { | ||
d.Set("authorization_key", conn.AuthorizationKey) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. providing this value is a string, we shouldn't need this check? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is an optional field in the API, is it then also safe to avoid this check? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since |
||
} | ||
|
||
if conn.Peer != nil { | ||
d.Set("express_route_circuit_id", conn.Peer.ID) | ||
|
@@ -194,9 +305,26 @@ func resourceArmVirtualNetworkGatewayConnectionRead(d *schema.ResourceData, meta | |
d.Set("local_network_gateway_id", conn.LocalNetworkGateway2.ID) | ||
} | ||
|
||
d.Set("enable_bgp", conn.EnableBgp) | ||
d.Set("routing_weight", conn.RoutingWeight) | ||
d.Set("shared_key", conn.SharedKey) | ||
if conn.EnableBgp != nil { | ||
d.Set("enable_bgp", conn.EnableBgp) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want to dereference this field? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is currently done in ResourceData.Set |
||
} | ||
|
||
if conn.UsePolicyBasedTrafficSelectors != nil { | ||
d.Set("use_policy_based_traffic_selectors", conn.UsePolicyBasedTrafficSelectors) | ||
} | ||
|
||
if conn.RoutingWeight != nil { | ||
d.Set("routing_weight", conn.RoutingWeight) | ||
} | ||
|
||
if conn.SharedKey != nil { | ||
d.Set("shared_key", conn.SharedKey) | ||
} | ||
|
||
if conn.IpsecPolicies != nil { | ||
ipsec_policies := flattenArmVirtualNetworkGatewayConnectionIpsecPolicies(conn.IpsecPolicies) | ||
d.Set("ipsec_policy", ipsec_policies) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. given this is a complex object, can we check for errors here via:
minor could we also rename the variable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding the variable naming, I found it helpful to quickly identify the source of which the value originates. I.e. I chose CamelCase for values from the Azure Go SDK whereas snake_case for value from the Terraform schema. However, to match the other resources, I will revert it. |
||
} | ||
|
||
flattenAndSetTags(d, resp.Tags) | ||
|
||
|
@@ -227,11 +355,9 @@ func resourceArmVirtualNetworkGatewayConnectionDelete(d *schema.ResourceData, me | |
|
||
func getArmVirtualNetworkGatewayConnectionProperties(d *schema.ResourceData) (*network.VirtualNetworkGatewayConnectionPropertiesFormat, error) { | ||
connectionType := network.VirtualNetworkGatewayConnectionType(d.Get("type").(string)) | ||
enableBgp := d.Get("enable_bgp").(bool) | ||
|
||
props := &network.VirtualNetworkGatewayConnectionPropertiesFormat{ | ||
ConnectionType: connectionType, | ||
EnableBgp: &enableBgp, | ||
} | ||
|
||
if v, ok := d.GetOk("virtual_network_gateway_id"); ok { | ||
|
@@ -294,14 +420,27 @@ func getArmVirtualNetworkGatewayConnectionProperties(d *schema.ResourceData) (*n | |
} | ||
} | ||
|
||
if v, ok := d.GetOk("enable_bgp"); ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if this is a bool, it'll always have a value (since the default is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea was to just not set the field in the API struct, if it is not defined in the Terraform schema instance. Is this overly safe? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's more this won't work as it reads unfortunately due to the way the defaults work in HCL (there's changes coming in this area in the future); given the field in the schema is a Boolean, there'll always be a default value of We could instead update this to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing to |
||
props.EnableBgp = utils.Bool(v.(bool)) | ||
} | ||
|
||
if v, ok := d.GetOk("use_policy_based_traffic_selectors"); ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (same here) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (same here) |
||
props.UsePolicyBasedTrafficSelectors = utils.Bool(v.(bool)) | ||
} | ||
|
||
if v, ok := d.GetOk("routing_weight"); ok { | ||
routingWeight := int32(v.(int)) | ||
props.RoutingWeight = &routingWeight | ||
routing_weight := int32(v.(int)) | ||
props.RoutingWeight = &routing_weight | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor could we revert this variable change? |
||
} | ||
|
||
if v, ok := d.GetOk("shared_key"); ok { | ||
sharedKey := v.(string) | ||
props.SharedKey = &sharedKey | ||
props.SharedKey = utils.String(v.(string)) | ||
} | ||
|
||
if v, ok := d.GetOk("ipsec_policy"); ok { | ||
ipsec_policies := v.([]interface{}) | ||
props.IpsecPolicies = expandArmVirtualNetworkGatewayConnectionIpsecPolicies(ipsec_policies) | ||
log.Printf("Ipsec policies: %+q", props.IpsecPolicies) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we remove this print statement? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, this is a true left over 😄 |
||
} | ||
|
||
if props.ConnectionType == network.ExpressRoute { | ||
|
@@ -339,3 +478,77 @@ func resourceGroupAndVirtualNetworkGatewayConnectionFromId(virtualNetworkGateway | |
|
||
return resGroup, name, nil | ||
} | ||
|
||
func expandArmVirtualNetworkGatewayConnectionIpsecPolicies(ipsec_policies []interface{}) *[]network.IpsecPolicy { | ||
ipsecPolicies := make([]network.IpsecPolicy, 0, len(ipsec_policies)) | ||
|
||
for _, d := range ipsec_policies { | ||
ipsec_policy := d.(map[string]interface{}) | ||
ipsecPolicy := &network.IpsecPolicy{} | ||
|
||
if dh_group, ok := ipsec_policy["dh_group"].(string); ok && dh_group != "" { | ||
ipsecPolicy.DhGroup = network.DhGroup(dh_group) | ||
} | ||
|
||
if ike_encryption, ok := ipsec_policy["ike_encryption"].(string); ok && ike_encryption != "" { | ||
ipsecPolicy.IkeEncryption = network.IkeEncryption(ike_encryption) | ||
} | ||
|
||
if ike_integrity, ok := ipsec_policy["ike_integrity"].(string); ok && ike_integrity != "" { | ||
ipsecPolicy.IkeIntegrity = network.IkeIntegrity(ike_integrity) | ||
} | ||
|
||
if ipsec_encryption, ok := ipsec_policy["ipsec_encryption"].(string); ok && ipsec_encryption != "" { | ||
ipsecPolicy.IpsecEncryption = network.IpsecEncryption(ipsec_encryption) | ||
} | ||
|
||
if ipsec_integrity, ok := ipsec_policy["ipsec_integrity"].(string); ok && ipsec_integrity != "" { | ||
ipsecPolicy.IpsecIntegrity = network.IpsecIntegrity(ipsec_integrity) | ||
} | ||
|
||
if pfs_group, ok := ipsec_policy["pfs_group"].(string); ok && pfs_group != "" { | ||
ipsecPolicy.PfsGroup = network.PfsGroup(pfs_group) | ||
} | ||
|
||
if v, ok := ipsec_policy["sa_datasize"].(int); ok { | ||
sa_datasize := int32(v) | ||
ipsecPolicy.SaDataSizeKilobytes = &sa_datasize | ||
} | ||
|
||
if v, ok := ipsec_policy["sa_lifetime"].(int); ok { | ||
sa_lifetime := int32(v) | ||
ipsecPolicy.SaLifeTimeSeconds = &sa_lifetime | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor could we update all of these variables to use camelCase rather than snake_case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In particular in a mapping function like flattenArmVirtualNetworkGatewayConnectionIpsecPolicies, the two casing makes sense to differentiate between Terraform schema and struct of Azure Go SDK. |
||
|
||
ipsecPolicies = append(ipsecPolicies, *ipsecPolicy) | ||
} | ||
|
||
return &ipsecPolicies | ||
} | ||
|
||
func flattenArmVirtualNetworkGatewayConnectionIpsecPolicies(ipsecPolicies *[]network.IpsecPolicy) []interface{} { | ||
ipsec_policies := make([]interface{}, 0, len(*ipsecPolicies)) | ||
|
||
for _, ipsecPolicy := range *ipsecPolicies { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's a potential crash here if
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I shouldn't rely on the caller here |
||
ipsec_policy := make(map[string]interface{}) | ||
|
||
ipsec_policy["dh_group"] = string(ipsecPolicy.DhGroup) | ||
ipsec_policy["ike_encryption"] = string(ipsecPolicy.IkeEncryption) | ||
ipsec_policy["ike_integrity"] = string(ipsecPolicy.IkeIntegrity) | ||
ipsec_policy["ipsec_encryption"] = string(ipsecPolicy.IpsecEncryption) | ||
ipsec_policy["ipsec_integrity"] = string(ipsecPolicy.IpsecIntegrity) | ||
ipsec_policy["pfs_group"] = string(ipsecPolicy.PfsGroup) | ||
|
||
if ipsecPolicy.SaDataSizeKilobytes != nil { | ||
ipsec_policy["sa_datasize"] = int(*ipsecPolicy.SaDataSizeKilobytes) | ||
} | ||
|
||
if ipsecPolicy.SaLifeTimeSeconds != nil { | ||
ipsec_policy["sa_lifetime"] = int(*ipsecPolicy.SaLifeTimeSeconds) | ||
} | ||
|
||
ipsec_policies = append(ipsec_policies, ipsec_policy) | ||
} | ||
|
||
return ipsec_policies | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this same default returned from Azure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, false is the API default for enable_bgp. The intention for this change was to increase the transparency of the provider towards the API, i.e. allow the API to decide for the default. Unfortunately, the API docs are not quite elaborate on the default values (https://docs.microsoft.com/en-us/rest/api/network-gateway/virtualnetworkgatewayconnections/createorupdate).