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

Site to Site VPN logging #26637

Merged
merged 22 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cf2ffeb
WIP on VPN connection tunnel logs
bschaatsbergen Aug 21, 2022
b9a0726
Merge branch 'main' into f/site-to-site-vpn-logs
bschaatsbergen Sep 3, 2022
5c1e815
Merge branch 'main' into f/site-to-site-vpn-logs
bschaatsbergen Sep 3, 2022
46029fe
Set to `cloudwatch_log_options`
bschaatsbergen Sep 3, 2022
f078ebb
Compute the log options
bschaatsbergen Sep 3, 2022
28a66e4
WIP on a cloudWatchLogOptions test
bschaatsbergen Sep 3, 2022
af47f3a
fmt test config
bschaatsbergen Sep 4, 2022
75ad013
Add some guard clauses
bschaatsbergen Sep 4, 2022
dd4606b
fix expands, had some trouble passing down the interface
bschaatsbergen Sep 4, 2022
971224c
Remove irrelevant resource attribute checks
bschaatsbergen Sep 4, 2022
9db018c
remove schema set clauses
bschaatsbergen Sep 4, 2022
9b10c2e
Add log options to docs
bschaatsbergen Sep 4, 2022
a23ace3
tabs to spaces
bschaatsbergen Sep 4, 2022
d63f809
fmt cloudwatch log group
bschaatsbergen Sep 5, 2022
750c331
Offload possible log output formats to a values func
bschaatsbergen Sep 5, 2022
62ef470
Set log options to schema type list
bschaatsbergen Sep 5, 2022
3f51152
Add CHANGELOG entry.
ewbankkit Sep 6, 2022
2211802
r/aws_vpn_connection: Correct 'tunnel1_log_options' and 'tunnel2_log_…
ewbankkit Sep 6, 2022
2cc425e
r/aws_vpn_connection: Log options are Computed.
ewbankkit Sep 6, 2022
61ea349
'cloudwatch_log_options' is Optional.
ewbankkit Sep 6, 2022
733d8ed
Fix semgrep 'ci.caps2-in-const-name'.
ewbankkit Sep 6, 2022
b4c24ec
r/aws_vpn_connection: No log ARN or format if not enabled.
ewbankkit Sep 7, 2022
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
141 changes: 141 additions & 0 deletions internal/service/ec2/vpnsite_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,38 @@ func ResourceVPNConnection() *schema.Resource {
ValidateFunc: validation.StringInSlice(vpnTunnelOptionsIKEVersion_Values(), false),
},
},
"tunnel1_log_options": {
Type: schema.TypeSet,
bschaatsbergen marked this conversation as resolved.
Show resolved Hide resolved
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cloudwatch_log_options": {
Optional: true,
Type: schema.TypeSet,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"log_enabled": {
Type: schema.TypeBool,
Optional: true,
},
"log_group_arn": {
Type: schema.TypeString,
Optional: true,
},
"log_output_format": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"json", "text",
bschaatsbergen marked this conversation as resolved.
Show resolved Hide resolved
}, false),
},
},
},
},
},
},
},
"tunnel1_inside_cidr": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -369,6 +401,38 @@ func ResourceVPNConnection() *schema.Resource {
ValidateFunc: validation.StringInSlice(vpnTunnelOptionsIKEVersion_Values(), false),
},
},
"tunnel2_log_options": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cloudwatch_log_options": {
Optional: true,
Type: schema.TypeSet,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"log_enabled": {
Type: schema.TypeBool,
Optional: true,
},
"log_group_arn": {
Type: schema.TypeString,
Optional: true,
},
"log_output_format": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"json", "text",
}, false),
},
},
},
},
},
},
},
"tunnel2_inside_cidr": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -960,6 +1024,10 @@ func expandVPNTunnelOptionsSpecification(d *schema.ResourceData, prefix string)
}
}

if v, ok := d.GetOk(prefix + "log_options"); ok && v.(*schema.Set).Len() > 0 {
apiObject.LogOptions = expandVPNTunnelLogOptionsSpecification(d)
}
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved

if v, ok := d.GetOk(prefix + "phase1_dh_group_numbers"); ok {
for _, v := range v.(*schema.Set).List() {
apiObject.Phase1DHGroupNumbers = append(apiObject.Phase1DHGroupNumbers, &ec2.Phase1DHGroupNumbersRequestListValue{Value: aws.Int64(int64(v.(int)))})
Expand Down Expand Up @@ -1035,6 +1103,34 @@ func expandVPNTunnelOptionsSpecification(d *schema.ResourceData, prefix string)
return apiObject
}

func expandVPNTunnelLogOptionsSpecification(d *schema.ResourceData) *ec2.VpnTunnelLogOptionsSpecification {
apiObject := &ec2.VpnTunnelLogOptionsSpecification{}

if v, ok := d.GetOk("cloudwatch_log_options"); ok && v.(*schema.Set).Len() > 0 {
apiObject.CloudWatchLogOptions = expandCloudWatchLogOptionsSpecification(d)
}

return apiObject
}

func expandCloudWatchLogOptionsSpecification(d *schema.ResourceData) *ec2.CloudWatchLogOptionsSpecification {
apiObject := &ec2.CloudWatchLogOptionsSpecification{}

if v, ok := d.GetOk("log_enabled"); ok {
apiObject.LogEnabled = aws.Bool(v.(bool))
}

if v, ok := d.GetOk("log_group_arn"); ok {
apiObject.LogGroupArn = aws.String(v.(string))
}

if v, ok := d.GetOk("log_output_format"); ok {
apiObject.LogOutputFormat = aws.String(v.(string))
}

return apiObject
}

func expandModifyVPNTunnelOptionsSpecification(d *schema.ResourceData, prefix string) *ec2.ModifyVpnTunnelOptionsSpecification {
apiObject := &ec2.ModifyVpnTunnelOptionsSpecification{}
hasChange := false
Expand Down Expand Up @@ -1073,6 +1169,14 @@ func expandModifyVPNTunnelOptionsSpecification(d *schema.ResourceData, prefix st
hasChange = true
}

if key := prefix + "log_options"; d.HasChange(key) {
if v, ok := d.GetOk(key); ok && v.(*schema.Set).Len() > 0 {
apiObject.LogOptions = expandVPNTunnelLogOptionsSpecification(d)
}

hasChange = true
}

if key := prefix + "phase1_dh_group_numbers"; d.HasChange(key) {
if v, ok := d.GetOk(key); ok && v.(*schema.Set).Len() > 0 {
for _, v := range d.Get(key).(*schema.Set).List() {
Expand Down Expand Up @@ -1240,6 +1344,7 @@ func flattenTunnelOption(d *schema.ResourceData, prefix string, apiObject *ec2.T

d.Set(prefix+"dpd_timeout_action", apiObject.DpdTimeoutAction)
d.Set(prefix+"dpd_timeout_seconds", apiObject.DpdTimeoutSeconds)
d.Set(prefix+"log_options", []interface{}{flattenVPNTunnelLogOptions(apiObject.LogOptions)})

for _, v := range apiObject.IkeVersions {
s = append(s, v.Value)
Expand Down Expand Up @@ -1333,6 +1438,42 @@ func flattenVPNStaticRoutes(apiObjects []*ec2.VpnStaticRoute) []interface{} {
return tfList
}

func flattenVPNTunnelLogOptions(apiObject *ec2.VpnTunnelLogOptions) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.CloudWatchLogOptions; v != nil {
tfMap["cloudwatch_log_options"] = []interface{}{flattenCloudWatchLogOptions(v)}
}

return tfMap
}

func flattenCloudWatchLogOptions(apiObject *ec2.CloudWatchLogOptions) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.LogEnabled; v != nil {
tfMap["log_enabled"] = aws.BoolValue(v)
}

if v := apiObject.LogGroupArn; v != nil {
tfMap["log_group_arn"] = aws.StringValue(v)
}

if v := apiObject.LogOutputFormat; v != nil {
tfMap["log_output_format"] = aws.StringValue(v)
}

return tfMap
}

func flattenVGWTelemetry(apiObject *ec2.VgwTelemetry) map[string]interface{} {
if apiObject == nil {
return nil
Expand Down
83 changes: 83 additions & 0 deletions internal/service/ec2/vpnsite_connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,43 @@ func TestAccSiteVPNConnection_basic(t *testing.T) {
})
}

func TestAccSiteVPNConnection_cloudWatchLogOptions(t *testing.T) {
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
rBgpAsn := sdkacctest.RandIntRange(64512, 65534)
resourceName := "aws_vpn_connection.test"
var vpn ec2.VpnConnection

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccVPNConnectionDestroy,
Steps: []resource.TestStep{
{
Config: testAccSiteVPNConnectionConfig_cloudWatchLogOptions(rName, rBgpAsn),
Check: resource.ComposeAggregateTestCheckFunc(
testAccVPNConnectionExists(resourceName, &vpn),
acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpn-connection/vpn-.+`)),
resource.TestCheckResourceAttr(resourceName, "tunnel1_log_options.#", "1"),
resource.TestCheckResourceAttr(resourceName, "tunnel1_log_options.0.cloudwatch_log_options.#", "1"),
resource.TestCheckResourceAttr(resourceName, "tunnel1_log_options.0.cloudwatch_log_options.0.log_enabled", "true"),
resource.TestCheckResourceAttrPair(resourceName, "tunnel1_log_options.0.cloudwatch_log_options.0.log_group_arn", "aws_cloudwatch_log_group.default", "arn"),
resource.TestCheckResourceAttr(resourceName, "tunnel1_log_options.0.cloudwatch_log_options.0.log_output_format", "json"),
resource.TestCheckResourceAttr(resourceName, "tunnel2_log_options.#", "1"),
resource.TestCheckResourceAttr(resourceName, "tunnel2_log_options.0.cloudwatch_log_options.#", "1"),
resource.TestCheckResourceAttr(resourceName, "tunnel2_log_options.0.cloudwatch_log_options.0.log_enabled", "true"),
resource.TestCheckResourceAttrPair(resourceName, "tunnel2_log_options.0.cloudwatch_log_options.0.log_group_arn", "aws_cloudwatch_log_group.default", "arn"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccSiteVPNConnection_transitGatewayID(t *testing.T) {
var vpn ec2.VpnConnection
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
Expand Down Expand Up @@ -1572,6 +1609,52 @@ resource "aws_vpn_connection" "test" {
`, rName, rBgpAsn)
}

func testAccSiteVPNConnectionConfig_cloudWatchLogOptions(rName string, rBgpAsn int) string {
return fmt.Sprintf(`
resource "aws_vpn_gateway" "test" {
tags = {
Name = %[1]q
}
}

resource "aws_customer_gateway" "test" {
bgp_asn = %[2]d
ip_address = "178.0.0.1"
type = "ipsec.1"

tags = {
Name = %[1]q
}
}

resource "aws_cloudwatch_log_group" "default" {
name = %[1]q
}

resource "aws_vpn_connection" "test" {
vpn_gateway_id = aws_vpn_gateway.test.id
customer_gateway_id = aws_customer_gateway.test.id
type = "ipsec.1"

tunnel1_log_options {
cloudwatch_log_options {
log_enabled = true
log_group_arn = aws_cloudwatch_log_group.default.arn
log_output_format = "json"
}
}

tunnel2_log_options {
cloudwatch_log_options {
log_enabled = true
log_group_arn = aws_cloudwatch_log_group.default.arn
log_output_format = "json"
}
}
}
`, rName, rBgpAsn)
}

func testAccSiteVPNConnectionConfig_customerGatewayID(rName string, rBgpAsn1, rBgpAsn2 int) string {
return fmt.Sprintf(`
resource "aws_vpn_gateway" "test" {
Expand Down
16 changes: 16 additions & 0 deletions website/docs/r/vpn_connection.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ Other arguments:
* `tunnel2_dpd_timeout_seconds` - (Optional, Default `30`) The number of seconds after which a DPD timeout occurs for the second VPN tunnel. Valid value is equal or higher than `30`.
* `tunnel1_ike_versions` - (Optional) The IKE versions that are permitted for the first VPN tunnel. Valid values are `ikev1 | ikev2`.
* `tunnel2_ike_versions` - (Optional) The IKE versions that are permitted for the second VPN tunnel. Valid values are `ikev1 | ikev2`.
* `tunnel1_log_options` - (Optional) Options for logging VPN tunnel activity. See [Log Options](#log-options) below for more details.
* `tunnel2_log_options` - (Optional) Options for logging VPN tunnel activity. See [Log Options](#log-options) below for more details.
* `tunnel1_phase1_dh_group_numbers` - (Optional) List of one or more Diffie-Hellman group numbers that are permitted for the first VPN tunnel for phase 1 IKE negotiations. Valid values are ` 2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24`.
* `tunnel2_phase1_dh_group_numbers` - (Optional) List of one or more Diffie-Hellman group numbers that are permitted for the second VPN tunnel for phase 1 IKE negotiations. Valid values are ` 2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24`.
* `tunnel1_phase1_encryption_algorithms` - (Optional) List of one or more encryption algorithms that are permitted for the first VPN tunnel for phase 1 IKE negotiations. Valid values are `AES128 | AES256 | AES128-GCM-16 | AES256-GCM-16`.
Expand All @@ -181,6 +183,20 @@ Other arguments:
* `tunnel1_startup_action` - (Optional, Default `add`) The action to take when the establishing the tunnel for the first VPN connection. By default, your customer gateway device must initiate the IKE negotiation and bring up the tunnel. Specify start for AWS to initiate the IKE negotiation. Valid values are `add | start`.
* `tunnel2_startup_action` - (Optional, Default `add`) The action to take when the establishing the tunnel for the second VPN connection. By default, your customer gateway device must initiate the IKE negotiation and bring up the tunnel. Specify start for AWS to initiate the IKE negotiation. Valid values are `add | start`.

### Log Options

The `tunnel1_log_options` and `tunnel2_log_options` block supports the following arguments:

* `cloudwatch_log_options` - (Required) Options for sending VPN tunnel logs to CloudWatch. See [CloudWatch Log Options](#cloudwatch-log-options) below for more details.
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved

### CloudWatch Log Options

The `cloudwatch_log_options` blocks supports the following arguments:

* `log_enabled` - (Optional) Enable or disable VPN tunnel logging feature. The default is `false`.
* `log_group_arn` - (Optional) The Amazon Resource Name (ARN) of the CloudWatch log group to send logs to.
* `log_output_format` - (Optional) Set log format. Default format is json. Possible values are: `json` and `text`. The default is `json`.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:
Expand Down