From fc1c88382f8266c4e0f8601969a5ac73dc6f019b Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 12 Feb 2021 02:44:27 +0200 Subject: [PATCH] resource/aws_ssm_patch_baseline: Approved/Rejected patch enhancements, arn attribute, and validations (#11772) Output from acceptance testing in AWS Commercial: ``` --- PASS: TestAccAWSSSMPatchBaseline_disappears (11.66s) --- PASS: TestAccAWSSSMPatchBaseline_ApprovedPatchesNonSec (15.49s) --- PASS: TestAccAWSSSMPatchBaseline_RejectPatchesAction (15.51s) --- PASS: TestAccAWSSSMPatchBaseline_basic (24.91s) --- PASS: TestAccAWSSSMPatchBaseline_OperatingSystem (25.68s) --- PASS: TestAccAWSSSMPatchBaseline_tags (34.07s) ``` Output from acceptance testing in AWS GovCloud (US): ``` --- PASS: TestAccAWSSSMPatchBaseline_disappears (14.52s) --- PASS: TestAccAWSSSMPatchBaseline_RejectPatchesAction (19.65s) --- PASS: TestAccAWSSSMPatchBaseline_ApprovedPatchesNonSec (20.14s) --- PASS: TestAccAWSSSMPatchBaseline_basic (34.06s) --- PASS: TestAccAWSSSMPatchBaseline_OperatingSystem (34.41s) --- PASS: TestAccAWSSSMPatchBaseline_tags (46.50s) ``` --- .changelog/11772.txt | 12 ++ aws/resource_aws_ssm_patch_baseline.go | 133 +++++++++++++----- aws/resource_aws_ssm_patch_baseline_test.go | 121 ++++++++++++---- .../docs/r/ssm_patch_baseline.html.markdown | 3 + 4 files changed, 205 insertions(+), 64 deletions(-) create mode 100644 .changelog/11772.txt diff --git a/.changelog/11772.txt b/.changelog/11772.txt new file mode 100644 index 00000000000..af336b2664a --- /dev/null +++ b/.changelog/11772.txt @@ -0,0 +1,12 @@ +```release-note:enhancement +resource/aws_ssm_patch_baseline: Adds plan time validation for `name`, `description`, `global_filter.key`, `global_filter.values`, +`approved_patches`, `rejected_patches`, `approval_rule.approve_after_days`, `approval_rule.patch_filter.key`, and `approval_rule.patch_filter.values`. +``` + +```release-note:enhancement +resource/aws_ssm_patch_baseline: Add `approved_patches_enable_non_security` and `rejected_patches_action` arguments +``` + +```release-note:enhancement +resource/aws_ssm_patch_baseline: Adds `arn` attribute. +``` diff --git a/aws/resource_aws_ssm_patch_baseline.go b/aws/resource_aws_ssm_patch_baseline.go index fe64e3286df..70e29e3a081 100644 --- a/aws/resource_aws_ssm_patch_baseline.go +++ b/aws/resource_aws_ssm_patch_baseline.go @@ -3,8 +3,11 @@ package aws import ( "fmt" "log" + "regexp" + "strings" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ssm" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -22,14 +25,23 @@ func resourceAwsSsmPatchBaseline() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "name": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(3, 128), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_\-.]{3,128}$`), "must contain only alphanumeric, underscore, hyphen, or period characters"), + ), }, "description": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 1024), }, "global_filter": { @@ -39,13 +51,19 @@ func resourceAwsSsmPatchBaseline() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "key": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ssm.PatchFilterKey_Values(), false), }, "values": { Type: schema.TypeList, Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, + MaxItems: 20, + MinItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 64), + }, }, }, }, @@ -57,8 +75,9 @@ func resourceAwsSsmPatchBaseline() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "approve_after_days": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 100), }, "compliance_level": { @@ -81,13 +100,19 @@ func resourceAwsSsmPatchBaseline() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "key": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ssm.PatchFilterKey_Values(), false), }, "values": { Type: schema.TypeList, Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, + MaxItems: 20, + MinItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 64), + }, }, }, }, @@ -99,15 +124,21 @@ func resourceAwsSsmPatchBaseline() *schema.Resource { "approved_patches": { Type: schema.TypeSet, Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + MaxItems: 50, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 100), + }, }, "rejected_patches": { Type: schema.TypeSet, Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + MaxItems: 50, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 100), + }, }, "operating_system": { @@ -124,13 +155,23 @@ func resourceAwsSsmPatchBaseline() *schema.Resource { Default: ssm.PatchComplianceLevelUnspecified, ValidateFunc: validation.StringInSlice(ssm.PatchComplianceLevel_Values(), false), }, + "rejected_patches_action": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(ssm.PatchAction_Values(), false), + }, + "approved_patches_enable_non_security": { + Type: schema.TypeBool, + Optional: true, + }, "tags": tagsSchema(), }, } } func resourceAwsSsmPatchBaselineCreate(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*AWSClient).ssmconn + conn := meta.(*AWSClient).ssmconn params := &ssm.CreatePatchBaselineInput{ Name: aws.String(d.Get("name").(string)), @@ -162,7 +203,15 @@ func resourceAwsSsmPatchBaselineCreate(d *schema.ResourceData, meta interface{}) params.ApprovalRules = expandAwsSsmPatchRuleGroup(d) } - resp, err := ssmconn.CreatePatchBaseline(params) + if v, ok := d.GetOk("approved_patches_enable_non_security"); ok { + params.ApprovedPatchesEnableNonSecurity = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("rejected_patches_action"); ok { + params.RejectedPatchesAction = aws.String(v.(string)) + } + + resp, err := conn.CreatePatchBaseline(params) if err != nil { return err } @@ -172,7 +221,7 @@ func resourceAwsSsmPatchBaselineCreate(d *schema.ResourceData, meta interface{}) } func resourceAwsSsmPatchBaselineUpdate(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*AWSClient).ssmconn + conn := meta.(*AWSClient).ssmconn params := &ssm.UpdatePatchBaselineInput{ BaselineId: aws.String(d.Id()), @@ -206,20 +255,25 @@ func resourceAwsSsmPatchBaselineUpdate(d *schema.ResourceData, meta interface{}) params.GlobalFilters = expandAwsSsmPatchFilterGroup(d) } - _, err := ssmconn.UpdatePatchBaseline(params) - if err != nil { - if isAWSErr(err, ssm.ErrCodeDoesNotExistException, "") { - log.Printf("[WARN] Patch Baseline %s not found, removing from state", d.Id()) - d.SetId("") - return nil + if d.HasChange("approved_patches_enable_non_security") { + params.ApprovedPatchesEnableNonSecurity = aws.Bool(d.Get("approved_patches_enable_non_security").(bool)) + } + + if d.HasChange("rejected_patches_action") { + params.RejectedPatchesAction = aws.String(d.Get("rejected_patches_action").(string)) + } + + if d.HasChangesExcept("tags") { + _, err := conn.UpdatePatchBaseline(params) + if err != nil { + return fmt.Errorf("error updating SSM Patch Baseline (%s): %w", d.Id(), err) } - return err } if d.HasChange("tags") { o, n := d.GetChange("tags") - if err := keyvaluetags.SsmUpdateTags(ssmconn, d.Id(), ssm.ResourceTypeForTaggingPatchBaseline, o, n); err != nil { + if err := keyvaluetags.SsmUpdateTags(conn, d.Id(), ssm.ResourceTypeForTaggingPatchBaseline, o, n); err != nil { return fmt.Errorf("error updating SSM Patch Baseline (%s) tags: %s", d.Id(), err) } } @@ -227,14 +281,14 @@ func resourceAwsSsmPatchBaselineUpdate(d *schema.ResourceData, meta interface{}) return resourceAwsSsmPatchBaselineRead(d, meta) } func resourceAwsSsmPatchBaselineRead(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*AWSClient).ssmconn + conn := meta.(*AWSClient).ssmconn ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig params := &ssm.GetPatchBaselineInput{ BaselineId: aws.String(d.Id()), } - resp, err := ssmconn.GetPatchBaseline(params) + resp, err := conn.GetPatchBaseline(params) if err != nil { if isAWSErr(err, ssm.ErrCodeDoesNotExistException, "") { log.Printf("[WARN] Patch Baseline %s not found, removing from state", d.Id()) @@ -250,6 +304,8 @@ func resourceAwsSsmPatchBaselineRead(d *schema.ResourceData, meta interface{}) e d.Set("approved_patches_compliance_level", resp.ApprovedPatchesComplianceLevel) d.Set("approved_patches", flattenStringList(resp.ApprovedPatches)) d.Set("rejected_patches", flattenStringList(resp.RejectedPatches)) + d.Set("rejected_patches_action", resp.RejectedPatchesAction) + d.Set("approved_patches_enable_non_security", resp.ApprovedPatchesEnableNonSecurity) if err := d.Set("global_filter", flattenAwsSsmPatchFilterGroup(resp.GlobalFilters)); err != nil { return fmt.Errorf("Error setting global filters error: %#v", err) @@ -259,7 +315,16 @@ func resourceAwsSsmPatchBaselineRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error setting approval rules error: %#v", err) } - tags, err := keyvaluetags.SsmListTags(ssmconn, d.Id(), ssm.ResourceTypeForTaggingPatchBaseline) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "ssm", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("patchbaseline/%s", strings.TrimPrefix(d.Id(), "/")), + } + d.Set("arn", arn.String()) + + tags, err := keyvaluetags.SsmListTags(conn, d.Id(), ssm.ResourceTypeForTaggingPatchBaseline) if err != nil { return fmt.Errorf("error listing tags for SSM Patch Baseline (%s): %s", d.Id(), err) @@ -273,7 +338,7 @@ func resourceAwsSsmPatchBaselineRead(d *schema.ResourceData, meta interface{}) e } func resourceAwsSsmPatchBaselineDelete(d *schema.ResourceData, meta interface{}) error { - ssmconn := meta.(*AWSClient).ssmconn + conn := meta.(*AWSClient).ssmconn log.Printf("[INFO] Deleting SSM Patch Baseline: %s", d.Id()) @@ -281,7 +346,7 @@ func resourceAwsSsmPatchBaselineDelete(d *schema.ResourceData, meta interface{}) BaselineId: aws.String(d.Id()), } - _, err := ssmconn.DeletePatchBaseline(params) + _, err := conn.DeletePatchBaseline(params) if err != nil { return fmt.Errorf("error deleting SSM Patch Baseline (%s): %s", d.Id(), err) } @@ -319,7 +384,7 @@ func flattenAwsSsmPatchFilterGroup(group *ssm.PatchFilterGroup) []map[string]int for _, filter := range group.PatchFilters { f := make(map[string]interface{}) - f["key"] = *filter.Key + f["key"] = aws.StringValue(filter.Key) f["values"] = flattenStringList(filter.Values) result = append(result, f) @@ -378,9 +443,9 @@ func flattenAwsSsmPatchRuleGroup(group *ssm.PatchRuleGroup) []map[string]interfa for _, rule := range group.PatchRules { r := make(map[string]interface{}) - r["approve_after_days"] = *rule.ApproveAfterDays - r["compliance_level"] = *rule.ComplianceLevel - r["enable_non_security"] = *rule.EnableNonSecurity + r["approve_after_days"] = aws.Int64Value(rule.ApproveAfterDays) + r["compliance_level"] = aws.StringValue(rule.ComplianceLevel) + r["enable_non_security"] = aws.BoolValue(rule.EnableNonSecurity) r["patch_filter"] = flattenAwsSsmPatchFilterGroup(rule.PatchFilterGroup) result = append(result, r) } diff --git a/aws/resource_aws_ssm_patch_baseline_test.go b/aws/resource_aws_ssm_patch_baseline_test.go index dc0881fdfb0..f9f40f2bda9 100644 --- a/aws/resource_aws_ssm_patch_baseline_test.go +++ b/aws/resource_aws_ssm_patch_baseline_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -14,7 +15,7 @@ import ( func TestAccAWSSSMPatchBaseline_basic(t *testing.T) { var before, after ssm.PatchBaselineIdentity name := acctest.RandString(10) - resourceName := "aws_ssm_patch_baseline.foo" + resourceName := "aws_ssm_patch_baseline.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -24,12 +25,14 @@ func TestAccAWSSSMPatchBaseline_basic(t *testing.T) { Config: testAccAWSSSMPatchBaselineBasicConfig(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSSMPatchBaselineExists(resourceName, &before), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ssm", regexp.MustCompile(`patchbaseline/pb-.+`)), resource.TestCheckResourceAttr(resourceName, "approved_patches.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "approved_patches.*", "KB123456"), resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("patch-baseline-%s", name)), resource.TestCheckResourceAttr(resourceName, "approved_patches_compliance_level", ssm.PatchComplianceLevelCritical), resource.TestCheckResourceAttr(resourceName, "description", "Baseline containing all updates approved for production systems"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "approved_patches_enable_non_security", "false"), ), }, { @@ -41,6 +44,7 @@ func TestAccAWSSSMPatchBaseline_basic(t *testing.T) { Config: testAccAWSSSMPatchBaselineBasicConfigUpdated(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSSMPatchBaselineExists(resourceName, &after), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ssm", regexp.MustCompile(`patchbaseline/pb-.+`)), resource.TestCheckResourceAttr(resourceName, "approved_patches.#", "2"), resource.TestCheckTypeSetElemAttr(resourceName, "approved_patches.*", "KB123456"), resource.TestCheckTypeSetElemAttr(resourceName, "approved_patches.*", "KB456789"), @@ -49,7 +53,7 @@ func TestAccAWSSSMPatchBaseline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", "Baseline containing all updates approved for production systems - August 2017"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), func(*terraform.State) error { - if *before.BaselineId != *after.BaselineId { + if aws.StringValue(before.BaselineId) != aws.StringValue(after.BaselineId) { t.Fatal("Baseline IDs changed unexpectedly") } return nil @@ -63,7 +67,7 @@ func TestAccAWSSSMPatchBaseline_basic(t *testing.T) { func TestAccAWSSSMPatchBaseline_tags(t *testing.T) { var patch ssm.PatchBaselineIdentity name := acctest.RandString(10) - resourceName := "aws_ssm_patch_baseline.foo" + resourceName := "aws_ssm_patch_baseline.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -106,7 +110,7 @@ func TestAccAWSSSMPatchBaseline_tags(t *testing.T) { func TestAccAWSSSMPatchBaseline_disappears(t *testing.T) { var identity ssm.PatchBaselineIdentity name := acctest.RandString(10) - resourceName := "aws_ssm_patch_baseline.foo" + resourceName := "aws_ssm_patch_baseline.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -117,7 +121,7 @@ func TestAccAWSSSMPatchBaseline_disappears(t *testing.T) { Config: testAccAWSSSMPatchBaselineBasicConfig(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSSMPatchBaselineExists(resourceName, &identity), - testAccCheckAWSSSMPatchBaselineDisappears(&identity), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSsmPatchBaseline(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -128,7 +132,7 @@ func TestAccAWSSSMPatchBaseline_disappears(t *testing.T) { func TestAccAWSSSMPatchBaseline_OperatingSystem(t *testing.T) { var before, after ssm.PatchBaselineIdentity name := acctest.RandString(10) - resourceName := "aws_ssm_patch_baseline.foo" + resourceName := "aws_ssm_patch_baseline.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -167,6 +171,56 @@ func TestAccAWSSSMPatchBaseline_OperatingSystem(t *testing.T) { }) } +func TestAccAWSSSMPatchBaseline_ApprovedPatchesNonSec(t *testing.T) { + var ssmPatch ssm.PatchBaselineIdentity + name := acctest.RandString(10) + resourceName := "aws_ssm_patch_baseline.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSSMPatchBaselineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSSMPatchBaselineBasicConfigApprovedPatchesNonSec(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSSMPatchBaselineExists(resourceName, &ssmPatch), + resource.TestCheckResourceAttr(resourceName, "approved_patches_enable_non_security", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSSSMPatchBaseline_RejectPatchesAction(t *testing.T) { + var ssmPatch ssm.PatchBaselineIdentity + name := acctest.RandString(10) + resourceName := "aws_ssm_patch_baseline.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSSMPatchBaselineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSSMPatchBaselineBasicConfigRejectPatchesAction(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSSMPatchBaselineExists(resourceName, &ssmPatch), + resource.TestCheckResourceAttr(resourceName, "rejected_patches_action", "ALLOW_AS_DEPENDENCY"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAwsSsmPatchBaselineRecreated(t *testing.T, before, after *ssm.PatchBaselineIdentity) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -213,24 +267,6 @@ func testAccCheckAWSSSMPatchBaselineExists(n string, patch *ssm.PatchBaselineIde } } -func testAccCheckAWSSSMPatchBaselineDisappears(patch *ssm.PatchBaselineIdentity) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ssmconn - - id := aws.StringValue(patch.BaselineId) - params := &ssm.DeletePatchBaselineInput{ - BaselineId: aws.String(id), - } - - _, err := conn.DeletePatchBaseline(params) - if err != nil { - return fmt.Errorf("error deleting Patch Baseline %s: %s", id, err) - } - - return nil - } -} - func testAccCheckAWSSSMPatchBaselineDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ssmconn @@ -264,7 +300,7 @@ func testAccCheckAWSSSMPatchBaselineDestroy(s *terraform.State) error { func testAccAWSSSMPatchBaselineBasicConfig(rName string) string { return fmt.Sprintf(` -resource "aws_ssm_patch_baseline" "foo" { +resource "aws_ssm_patch_baseline" "test" { name = "patch-baseline-%s" description = "Baseline containing all updates approved for production systems" approved_patches = ["KB123456"] @@ -275,7 +311,7 @@ resource "aws_ssm_patch_baseline" "foo" { func testAccAWSSSMPatchBaselineBasicConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` -resource "aws_ssm_patch_baseline" "foo" { +resource "aws_ssm_patch_baseline" "test" { name = %[1]q description = "Baseline containing all updates approved for production systems" approved_patches = ["KB123456"] @@ -290,7 +326,7 @@ resource "aws_ssm_patch_baseline" "foo" { func testAccAWSSSMPatchBaselineBasicConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` -resource "aws_ssm_patch_baseline" "foo" { +resource "aws_ssm_patch_baseline" "test" { name = %[1]q description = "Baseline containing all updates approved for production systems" approved_patches = ["KB123456"] @@ -306,7 +342,7 @@ resource "aws_ssm_patch_baseline" "foo" { func testAccAWSSSMPatchBaselineBasicConfigUpdated(rName string) string { return fmt.Sprintf(` -resource "aws_ssm_patch_baseline" "foo" { +resource "aws_ssm_patch_baseline" "test" { name = "updated-patch-baseline-%s" description = "Baseline containing all updates approved for production systems - August 2017" approved_patches = ["KB123456", "KB456789"] @@ -317,7 +353,7 @@ resource "aws_ssm_patch_baseline" "foo" { func testAccAWSSSMPatchBaselineConfigWithOperatingSystem(rName string) string { return fmt.Sprintf(` -resource "aws_ssm_patch_baseline" "foo" { +resource "aws_ssm_patch_baseline" "test" { name = "patch-baseline-%s" operating_system = "AMAZON_LINUX" description = "Baseline containing all updates approved for production systems" @@ -347,7 +383,7 @@ resource "aws_ssm_patch_baseline" "foo" { func testAccAWSSSMPatchBaselineConfigWithOperatingSystemUpdated(rName string) string { return fmt.Sprintf(` -resource "aws_ssm_patch_baseline" "foo" { +resource "aws_ssm_patch_baseline" "test" { name = "patch-baseline-%s" operating_system = "WINDOWS" description = "Baseline containing all updates approved for production systems" @@ -373,3 +409,28 @@ resource "aws_ssm_patch_baseline" "foo" { } `, rName) } + +func testAccAWSSSMPatchBaselineBasicConfigApprovedPatchesNonSec(rName string) string { + return fmt.Sprintf(` +resource "aws_ssm_patch_baseline" "test" { + name = %q + operating_system = "AMAZON_LINUX" + description = "Baseline containing all updates approved for production systems" + approved_patches = ["KB123456"] + approved_patches_compliance_level = "CRITICAL" + approved_patches_enable_non_security = true +} +`, rName) +} + +func testAccAWSSSMPatchBaselineBasicConfigRejectPatchesAction(rName string) string { + return fmt.Sprintf(` +resource "aws_ssm_patch_baseline" "test" { + name = "patch-baseline-%s" + description = "Baseline containing all updates approved for production systems" + approved_patches = ["KB123456"] + approved_patches_compliance_level = "CRITICAL" + rejected_patches_action = "ALLOW_AS_DEPENDENCY" +} +`, rName) +} diff --git a/website/docs/r/ssm_patch_baseline.html.markdown b/website/docs/r/ssm_patch_baseline.html.markdown index 48a02bbd29d..2aa5a891132 100644 --- a/website/docs/r/ssm_patch_baseline.html.markdown +++ b/website/docs/r/ssm_patch_baseline.html.markdown @@ -132,6 +132,8 @@ The following arguments are supported: * `rejected_patches` - (Optional) A list of rejected patches. * `global_filter` - (Optional) A set of global filters used to exclude patches from the baseline. Up to 4 global filters can be specified using Key/Value pairs. Valid Keys are `PRODUCT | CLASSIFICATION | MSRC_SEVERITY | PATCH_ID`. * `approval_rule` - (Optional) A set of rules used to include patches in the baseline. up to 10 approval rules can be specified. Each approval_rule block requires the fields documented below. +* `rejected_patches_action` - (Optional) The action for Patch Manager to take on patches included in the `rejected_patches` list. Allow values are `ALLOW_AS_DEPENDENCY` and `BLOCK`. +* `approved_patches_enable_non_security` - (Optional) Indicates whether the list of approved patches includes non-security updates that should be applied to the instances. Applies to Linux instances only. The `approval_rule` block supports: @@ -147,6 +149,7 @@ The `approval_rule` block supports: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the patch baseline. +* `arn` - The ARN of the patch baseline. ## Import