diff --git a/examples/resource_lacework_integration_ecr/main.tf b/examples/resource_lacework_integration_ecr/main.tf index 27dbc90a..7c4fd49d 100644 --- a/examples/resource_lacework_integration_ecr/main.tf +++ b/examples/resource_lacework_integration_ecr/main.tf @@ -1,12 +1,24 @@ provider "lacework" {} -resource "lacework_integration_ecr" "example" { - name = "ERC Example" - registry_domain = "YourAWSAccount.dkr.ecr.YourRegion.amazonaws.com" - access_key_id = "AWS123abcAccessKeyID" - secret_access_key = "AWS123abc123abcSecretAccessKey0000000000" - limit_by_tag = "dev*" - limit_by_label = "*label" - limit_by_repos = "my-repo,other-repo" - limit_num_imgs = 10 +resource "lacework_integration_ecr" "iam_role" { + name = "ECR using IAM Role" + registry_domain = "YourAWSAccount.dkr.ecr.YourRegion.amazonaws.com" + credentials { + role_arn = "arn:aws:iam::1234567890:role/lacework_iam_example_role" + external_id = "12345" + } +} + +resource "lacework_integration_ecr" "access_key" { + name = "ECR using Access Keys" + registry_domain = "YourAWSAccount.dkr.ecr.YourRegion.amazonaws.com" + credentials { + access_key_id = "AWS123abcAccessKeyID" + secret_access_key = "AWS123abc123abcSecretAccessKey0000000000" + } + + limit_by_tag = "dev*" + limit_by_label = "*label" + limit_by_repos = "my-repo,other-repo" + limit_num_imgs = 10 } diff --git a/lacework/resource_lacework_integration_ecr.go b/lacework/resource_lacework_integration_ecr.go index 3cad50f1..c2c9752f 100644 --- a/lacework/resource_lacework_integration_ecr.go +++ b/lacework/resource_lacework_integration_ecr.go @@ -1,13 +1,51 @@ package lacework import ( + "fmt" "log" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/pkg/errors" "github.com/lacework/go-sdk/api" ) +func importLaceworkECRIntegration(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + lacework := meta.(*api.Client) + + log.Printf("[INFO] Importing Lacework integration with guid: %s\n", d.Id()) + response, err := lacework.Integrations.Get(d.Id()) + if err != nil { + return nil, err + } + + for _, integration := range response.Data { + if integration.IntgGuid == d.Id() { + log.Printf("[INFO] Integration found with guid: %v\n", integration.IntgGuid) + + // @afiune this field is important since it tells the resource which API functions to use + // we will extract it from the raw integration response so that the READ functions populate + // the rest of the fiels + if awsAuthType, ok := integration.Data["AWS_AUTH_TYPE"]; ok { + d.Set("aws_auth_type", awsAuthType.(string)) + } else { + // if this field does not exist, the user might be importing a wrong integration type + // (or the SCHEMA changed again without notice...) + return nil, errors.New("AWS_AUTH_TYPE not found. Are you importing an ECR integration?") + } + + log.Printf("[INFO] ECR integration found with guid: %v\n", integration.IntgGuid) + return []*schema.ResourceData{d}, nil + } + } + + log.Printf("[INFO] Raw integration response: %v\n", response) + return nil, fmt.Errorf( + "Unable to import Lacework resource. Integration with guid '%s' was not found.", + d.Id(), + ) +} + func resourceLaceworkIntegrationEcr() *schema.Resource { return &schema.Resource{ Create: resourceLaceworkIntegrationEcrCreate, @@ -16,7 +54,7 @@ func resourceLaceworkIntegrationEcr() *schema.Resource { Delete: resourceLaceworkIntegrationEcrDelete, Importer: &schema.ResourceImporter{ - State: importLaceworkIntegration, + State: importLaceworkECRIntegration, }, Schema: map[string]*schema.Schema{ @@ -33,14 +71,32 @@ func resourceLaceworkIntegrationEcr() *schema.Resource { Type: schema.TypeString, Required: true, }, - "access_key_id": { - Type: schema.TypeString, + "credentials": { + Type: schema.TypeList, + MaxItems: 1, Required: true, - }, - "secret_access_key": { - Type: schema.TypeString, - Required: true, - Sensitive: true, + //ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "role_arn": { + Type: schema.TypeString, + Optional: true, + }, + "external_id": { + Type: schema.TypeString, + Optional: true, + }, + "access_key_id": { + Type: schema.TypeString, + Optional: true, + }, + "secret_access_key": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + }, + }, }, "limit_by_tag": { Type: schema.TypeString, @@ -62,6 +118,10 @@ func resourceLaceworkIntegrationEcr() *schema.Resource { Optional: true, Default: 5, }, + "aws_auth_type": { + Type: schema.TypeString, + Computed: true, + }, "intg_guid": { Type: schema.TypeString, Computed: true, @@ -88,58 +148,93 @@ func resourceLaceworkIntegrationEcr() *schema.Resource { func resourceLaceworkIntegrationEcrCreate(d *schema.ResourceData, meta interface{}) error { lacework := meta.(*api.Client) - data := api.NewAwsEcrWithAccessKeyIntegration(d.Get("name").(string), - api.AwsEcrDataWithAccessKeyCreds{ - Credentials: api.AwsEcrAccessKeyCreds{ - AccessKeyID: d.Get("access_key_id").(string), - SecretAccessKey: d.Get("secret_access_key").(string), - }, - AwsEcrCommonData: api.AwsEcrCommonData{ - LimitByTag: d.Get("limit_by_tag").(string), - LimitByLabel: d.Get("limit_by_label").(string), - LimitByRep: d.Get("limit_by_repos").(string), - LimitNumImg: d.Get("limit_num_imgs").(int), - RegistryDomain: d.Get("registry_domain").(string), - }, - }, - ) - if !d.Get("enabled").(bool) { - data.Enabled = 0 + switch detectAuthenticationMethod(d) { + case api.AwsEcrAccessKey.String(): + return resourceLaceworkIntegrationEcrCreateWithAccessKey(d, lacework) + + case api.AwsEcrIAM.String(): + return resourceLaceworkIntegrationEcrCreateWithIAMRole(d, lacework) + + default: + msg := `Invalid credentials block. + +For AWS IAM Role-Based Authentication, provide only the arguments: + * role_arn + * external_id + +For AWS Access Key-Based Authentication, provide only the arguments: + * access_key_id + * secret_access_key + +For more information visit https://registry.terraform.io/providers/lacework/lacework/latest/docs/resources/integration_ecr +` + return errors.New(msg) } +} - log.Printf("[INFO] Creating %s integration %s registry type with data:\n%+v\n", - api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), data) - response, err := lacework.Integrations.CreateAwsEcrWithAccessKey(data) +func resourceLaceworkIntegrationEcrRead(d *schema.ResourceData, meta interface{}) error { + lacework := meta.(*api.Client) + + switch d.Get("aws_auth_type").(string) { + case api.AwsEcrAccessKey.String(): + log.Printf("[INFO] %s Authentication: %s\n", api.EcrRegistry.String(), api.AwsEcrAccessKey.String()) + return resourceLaceworkIntegrationEcrReadWithAccessKey(d, lacework) + + case api.AwsEcrIAM.String(): + log.Printf("[INFO] %s Authentication: %s\n", api.EcrRegistry.String(), api.AwsEcrIAM.String()) + return resourceLaceworkIntegrationEcrReadWithIAMRole(d, lacework) + + default: + return errors.Errorf("Unsupported ECR authentication type '%s'.", d.Get("aws_auth_type").(string)) + } +} + +func resourceLaceworkIntegrationEcrReadWithIAMRole(d *schema.ResourceData, lacework *api.Client) error { + log.Printf("[INFO] Reading %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), d.Id()) + response, err := lacework.Integrations.GetAwsEcrWithCrossAccount(d.Id()) if err != nil { return err } for _, integration := range response.Data { - d.SetId(integration.IntgGuid) - d.Set("name", integration.Name) - d.Set("intg_guid", integration.IntgGuid) - d.Set("enabled", integration.Enabled == 1) - d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime) - d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy) - d.Set("type_name", integration.TypeName) - d.Set("org_level", integration.IsOrg == 1) + if integration.IntgGuid == d.Id() { + d.Set("name", integration.Name) + d.Set("intg_guid", integration.IntgGuid) + d.Set("enabled", integration.Enabled == 1) + d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy) + d.Set("type_name", integration.TypeName) + d.Set("org_level", integration.IsOrg == 1) + // @afiune this field is important for updates since it will force a new resource + d.Set("aws_auth_type", integration.Data.AwsAuthType) + d.Set("registry_domain", integration.Data.RegistryDomain) + + creds := make(map[string]string) + creds["role_arn"] = integration.Data.Credentials.RoleArn + creds["external_id"] = integration.Data.Credentials.ExternalID + d.Set("credentials", []map[string]string{creds}) + + d.Set("limit_by_tag", integration.Data.LimitByTag) + d.Set("limit_by_label", integration.Data.LimitByLabel) + d.Set("limit_by_repos", integration.Data.LimitByRep) + d.Set("limit_num_imgs", integration.Data.LimitNumImg) - log.Printf("[INFO] Created %s integration %s registry type with guid: %v\n", - api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), integration.IntgGuid) - return nil + log.Printf("[INFO] Read %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), integration.IntgGuid) + return nil + } } + d.SetId("") return nil } -func resourceLaceworkIntegrationEcrRead(d *schema.ResourceData, meta interface{}) error { - lacework := meta.(*api.Client) - +func resourceLaceworkIntegrationEcrReadWithAccessKey(d *schema.ResourceData, lacework *api.Client) error { log.Printf("[INFO] Reading %s integration %s registry type with guid: %v\n", api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), d.Id()) response, err := lacework.Integrations.GetAwsEcrWithAccessKey(d.Id()) - if err != nil { return err } @@ -154,8 +249,14 @@ func resourceLaceworkIntegrationEcrRead(d *schema.ResourceData, meta interface{} d.Set("type_name", integration.TypeName) d.Set("org_level", integration.IsOrg == 1) - d.Set("access_key_id", integration.Data.Credentials.AccessKeyID) + // @afiune this field is important for updates since it will force a new resource + d.Set("aws_auth_type", integration.Data.AwsAuthType) d.Set("registry_domain", integration.Data.RegistryDomain) + + creds := make(map[string]string) + creds["access_key_id"] = integration.Data.Credentials.AccessKeyID + d.Set("credentials", []map[string]string{creds}) + d.Set("limit_by_tag", integration.Data.LimitByTag) d.Set("limit_by_label", integration.Data.LimitByLabel) d.Set("limit_by_repos", integration.Data.LimitByRep) @@ -173,11 +274,125 @@ func resourceLaceworkIntegrationEcrRead(d *schema.ResourceData, meta interface{} func resourceLaceworkIntegrationEcrUpdate(d *schema.ResourceData, meta interface{}) error { lacework := meta.(*api.Client) + + switch d.Get("aws_auth_type").(string) { + case api.AwsEcrAccessKey.String(): + log.Printf("[INFO] %s Authentication: %s\n", api.EcrRegistry.String(), api.AwsEcrAccessKey.String()) + + if err := validateAccessKeyCreds(d); err != nil { + // verify if the user is trying to change the authentication method + errIAM := validateIAMRoleCreds(d) + if errIAM != nil { + // nope, just throw the first error as usual + return err + } + + // yup, the user is trying to change the authentication method + // we need to delete the integration and create a new one + log.Println("[WARN] Change of authentication method detected. Need destroy and recreation") + log.Printf("[INFO] Deleting %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), d.Id()) + _, err := lacework.Integrations.Delete(d.Id()) + if err != nil { + return err + } + + return resourceLaceworkIntegrationEcrCreate(d, meta) + } + + return resourceLaceworkIntegrationEcrUpdateWithAccessKey(d, lacework) + + case api.AwsEcrIAM.String(): + log.Printf("[INFO] %s Authentication: %s\n", api.EcrRegistry.String(), api.AwsEcrIAM.String()) + + if err := validateIAMRoleCreds(d); err != nil { + // verify if the user is trying to change the authentication method + errKeys := validateAccessKeyCreds(d) + if errKeys != nil { + // nope, just throw the first error as usual + return err + } + + // yup, the user is trying to change the authentication method + // we need to delete the integration and create a new one + log.Println("[WARN] Change of authentication method detected. Need destroy and recreation") + log.Printf("[INFO] Deleting %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), d.Id()) + _, err := lacework.Integrations.Delete(d.Id()) + if err != nil { + return err + } + + return resourceLaceworkIntegrationEcrCreate(d, meta) + } + + return resourceLaceworkIntegrationEcrUpdateWithIAMRole(d, lacework) + + default: + return errors.Errorf("Unsupported ECR authentication type '%s'.", d.Get("aws_auth_type").(string)) + } +} + +func resourceLaceworkIntegrationEcrUpdateWithIAMRole(d *schema.ResourceData, lacework *api.Client) error { + data := api.NewAwsEcrWithCrossAccountIntegration(d.Get("name").(string), + api.AwsEcrDataWithCrossAccountCreds{ + Credentials: api.AwsCrossAccountCreds{ + RoleArn: d.Get("credentials.0.role_arn").(string), + ExternalID: d.Get("credentials.0.external_id").(string), + }, + AwsEcrCommonData: api.AwsEcrCommonData{ + LimitByTag: d.Get("limit_by_tag").(string), + LimitByLabel: d.Get("limit_by_label").(string), + LimitByRep: d.Get("limit_by_repos").(string), + LimitNumImg: d.Get("limit_num_imgs").(int), + RegistryDomain: d.Get("registry_domain").(string), + }, + }, + ) + + if !d.Get("enabled").(bool) { + data.Enabled = 0 + } + + data.IntgGuid = d.Id() + + log.Printf("[INFO] Updating %s integration %s registry with authentication %s\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), data.Data.AwsAuthType) + response, err := lacework.Integrations.UpdateAwsEcrWithCrossAccount(data) + if err != nil { + return err + } + + log.Printf("[INFO] Verifying server response") + err = validateEcrWithIAMRoleIntegrationResponse(&response) + if err != nil { + return err + } + + // @afiune at this point in time, we know the data field has a single value + integration := response.Data[0] + d.Set("name", integration.Name) + d.Set("intg_guid", integration.IntgGuid) + d.Set("enabled", integration.Enabled == 1) + d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy) + d.Set("type_name", integration.TypeName) + d.Set("org_level", integration.IsOrg == 1) + // @afiune this field is important for updates since it will force a new resource + d.Set("aws_auth_type", integration.Data.AwsAuthType) + + log.Printf("[INFO] Updated %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), d.Id()) + + return nil +} + +func resourceLaceworkIntegrationEcrUpdateWithAccessKey(d *schema.ResourceData, lacework *api.Client) error { data := api.NewAwsEcrWithAccessKeyIntegration(d.Get("name").(string), api.AwsEcrDataWithAccessKeyCreds{ Credentials: api.AwsEcrAccessKeyCreds{ - AccessKeyID: d.Get("access_key_id").(string), - SecretAccessKey: d.Get("secret_access_key").(string), + AccessKeyID: d.Get("credentials.0.access_key_id").(string), + SecretAccessKey: d.Get("credentials.0.secret_access_key").(string), }, AwsEcrCommonData: api.AwsEcrCommonData{ LimitByTag: d.Get("limit_by_tag").(string), @@ -195,30 +410,34 @@ func resourceLaceworkIntegrationEcrUpdate(d *schema.ResourceData, meta interface data.IntgGuid = d.Id() - log.Printf("[INFO] Updating %s integration %s registry type with data:\n%+v\n", - api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), data) + log.Printf("[INFO] Updating %s integration %s registry with authentication %s\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), data.Data.AwsAuthType) response, err := lacework.Integrations.UpdateAwsEcrWithAccessKey(data) if err != nil { return err } - for _, integration := range response.Data { - if integration.IntgGuid == d.Id() { - d.Set("name", integration.Name) - d.Set("intg_guid", integration.IntgGuid) - d.Set("enabled", integration.Enabled == 1) - d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime) - d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy) - d.Set("type_name", integration.TypeName) - d.Set("org_level", integration.IsOrg == 1) - - log.Printf("[INFO] Updated %s integration %s registry type with guid: %v\n", - api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), d.Id()) - - return nil - } + log.Printf("[INFO] Verifying server response") + err = validateEcrWithAccessKeyIntegrationResponse(&response) + if err != nil { + return err } + // @afiune at this point in time, we know the data field has a single value + integration := response.Data[0] + d.Set("name", integration.Name) + d.Set("intg_guid", integration.IntgGuid) + d.Set("enabled", integration.Enabled == 1) + d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy) + d.Set("type_name", integration.TypeName) + d.Set("org_level", integration.IsOrg == 1) + // @afiune this field is important for updates since it will force a new resource + d.Set("aws_auth_type", integration.Data.AwsAuthType) + + log.Printf("[INFO] Updated %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), d.Id()) + return nil } @@ -238,3 +457,215 @@ func resourceLaceworkIntegrationEcrDelete(d *schema.ResourceData, meta interface return nil } + +func detectAuthenticationMethod(d *schema.ResourceData) string { + if err := validateIAMRoleCreds(d); err == nil { + return api.AwsEcrIAM.String() + } + + if err := validateAccessKeyCreds(d); err == nil { + return api.AwsEcrAccessKey.String() + } + + return "credentials block misconfigured" +} + +func validateIAMRoleCreds(d *schema.ResourceData) error { + if d.Get("credentials.0.role_arn").(string) == "" { + return errors.New("missing role_arn argument inside credentials block.") + } + if d.Get("credentials.0.external_id").(string) == "" { + return errors.New("missing external_id argument inside credentials block.") + } + + return nil +} + +func validateAccessKeyCreds(d *schema.ResourceData) error { + if d.Get("credentials.0.access_key_id").(string) == "" { + return errors.New("missing access_key_id argument inside credentials block.") + } + if d.Get("credentials.0.secret_access_key").(string) == "" { + return errors.New("missing secret_access_key argument inside credentials block.") + } + + return nil +} + +func resourceLaceworkIntegrationEcrCreateWithAccessKey(d *schema.ResourceData, lacework *api.Client) error { + data := api.NewAwsEcrWithAccessKeyIntegration(d.Get("name").(string), + api.AwsEcrDataWithAccessKeyCreds{ + Credentials: api.AwsEcrAccessKeyCreds{ + AccessKeyID: d.Get("credentials.0.access_key_id").(string), + SecretAccessKey: d.Get("credentials.0.secret_access_key").(string), + }, + AwsEcrCommonData: api.AwsEcrCommonData{ + LimitByTag: d.Get("limit_by_tag").(string), + LimitByLabel: d.Get("limit_by_label").(string), + LimitByRep: d.Get("limit_by_repos").(string), + LimitNumImg: d.Get("limit_num_imgs").(int), + RegistryDomain: d.Get("registry_domain").(string), + }, + }, + ) + + log.Printf("[INFO] Creating %s integration %s registry with authentication %s\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), data.Data.AwsAuthType) + response, err := lacework.Integrations.CreateAwsEcrWithAccessKey(data) + if err != nil { + return err + } + + if !d.Get("enabled").(bool) { + data.Enabled = 0 + } + + log.Printf("[INFO] Verifying server response") + err = validateEcrWithAccessKeyIntegrationResponse(&response) + if err != nil { + return err + } + + // @afiune at this point in time, we know the data field has a single value + integration := response.Data[0] + d.SetId(integration.IntgGuid) + d.Set("name", integration.Name) + d.Set("intg_guid", integration.IntgGuid) + d.Set("enabled", integration.Enabled == 1) + d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy) + d.Set("type_name", integration.TypeName) + d.Set("org_level", integration.IsOrg == 1) + // @afiune this field is important for updates since it will force a new resource + d.Set("aws_auth_type", integration.Data.AwsAuthType) + + log.Printf("[INFO] Created %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), integration.IntgGuid) + return nil +} + +func resourceLaceworkIntegrationEcrCreateWithIAMRole(d *schema.ResourceData, lacework *api.Client) error { + data := api.NewAwsEcrWithCrossAccountIntegration(d.Get("name").(string), + api.AwsEcrDataWithCrossAccountCreds{ + Credentials: api.AwsCrossAccountCreds{ + RoleArn: d.Get("credentials.0.role_arn").(string), + ExternalID: d.Get("credentials.0.external_id").(string), + }, + AwsEcrCommonData: api.AwsEcrCommonData{ + LimitByTag: d.Get("limit_by_tag").(string), + LimitByLabel: d.Get("limit_by_label").(string), + LimitByRep: d.Get("limit_by_repos").(string), + LimitNumImg: d.Get("limit_num_imgs").(int), + RegistryDomain: d.Get("registry_domain").(string), + }, + }, + ) + + log.Printf("[INFO] Creating %s integration %s registry with authentication %s\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), data.Data.AwsAuthType) + response, err := lacework.Integrations.CreateAwsEcrWithCrossAccount(data) + if err != nil { + return err + } + + if !d.Get("enabled").(bool) { + data.Enabled = 0 + } + + log.Printf("[INFO] Verifying server response") + err = validateEcrWithIAMRoleIntegrationResponse(&response) + if err != nil { + return err + } + + // @afiune at this point in time, we know the data field has a single value + integration := response.Data[0] + d.SetId(integration.IntgGuid) + d.Set("name", integration.Name) + d.Set("intg_guid", integration.IntgGuid) + d.Set("enabled", integration.Enabled == 1) + d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy) + d.Set("type_name", integration.TypeName) + d.Set("org_level", integration.IsOrg == 1) + // @afiune this field is important for updates since it will force a new resource + d.Set("aws_auth_type", integration.Data.AwsAuthType) + + log.Printf("[INFO] Created %s integration %s registry type with guid: %v\n", + api.ContainerRegistryIntegration.String(), api.EcrRegistry.String(), integration.IntgGuid) + return nil +} + +// validateEcrWithIAMRoleIntegrationResponse checks weather or not the server +// response has any inconsistent data, it returns a friendly error message describing +// the problem and how to report it +func validateEcrWithIAMRoleIntegrationResponse( + response *api.AwsEcrWithCrossAccountIntegrationResponse) error { + if len(response.Data) == 0 { + // @afiune this edge case should never happen, if we land here it means that + // something went wrong in the server side of things (Lacework API), so let + // us inform that to our users + msg := ` +Unable to read sever response data. (empty 'data' field) + +This was an unexpected behavior, verify that your integration has been +created successfully and report this issue to support@lacework.net +` + return fmt.Errorf(msg) + } + + if len(response.Data) > 1 { + // @afiune if we are creating a single integration and the server returns + // more than one integration inside the 'data' field, it is definitely another + // edge case that should never happen + msg := ` +There is more that one integration inside the server response data. + +List of integrations: +` + for _, integration := range response.Data { + msg = msg + fmt.Sprintf("\t%s: %s\n", integration.IntgGuid, integration.Name) + } + msg = msg + unexpectedBehaviorMsg() + return fmt.Errorf(msg) + } + + return nil +} + +// validateEcrWithAccessKeyIntegrationResponse checks weather or not the server +// response has any inconsistent data, it returns a friendly error message describing +// the problem and how to report it +func validateEcrWithAccessKeyIntegrationResponse( + response *api.AwsEcrWithAccessKeyIntegrationResponse) error { + if len(response.Data) == 0 { + // @afiune this edge case should never happen, if we land here it means that + // something went wrong in the server side of things (Lacework API), so let + // us inform that to our users + msg := ` +Unable to read sever response data. (empty 'data' field) + +This was an unexpected behavior, verify that your integration has been +created successfully and report this issue to support@lacework.net +` + return fmt.Errorf(msg) + } + + if len(response.Data) > 1 { + // @afiune if we are creating a single integration and the server returns + // more than one integration inside the 'data' field, it is definitely another + // edge case that should never happen + msg := ` +There is more that one integration inside the server response data. + +List of integrations: +` + for _, integration := range response.Data { + msg = msg + fmt.Sprintf("\t%s: %s\n", integration.IntgGuid, integration.Name) + } + msg = msg + unexpectedBehaviorMsg() + return fmt.Errorf(msg) + } + + return nil +} diff --git a/website/docs/r/integration_ecr.html.markdown b/website/docs/r/integration_ecr.html.markdown index af98f429..f918163d 100644 --- a/website/docs/r/integration_ecr.html.markdown +++ b/website/docs/r/integration_ecr.html.markdown @@ -12,13 +12,19 @@ Use this resource to integrate an Amazon Container Registry (ECR) with Lacework and report vulnerabilities found in the operating system software packages in a Docker container image. -~> **Note:** Assessing a retagged ECR image is not supported because ECR does not consider it a new image and does not create a new entry. To assess a retagged image, use on-demand assessment through the Lacework CLI. For more information, see the [container vulnerability section in the Lacework CLI documentation](https://github.com/lacework/go-sdk/wiki/CLI-Documentation#container-vulnerability-assessments). +~> **Note:** Assessing a retagged ECR image is not supported because ECR does not consider it a new +image and does not create a new entry. To assess a retagged image, use on-demand assessment through +the Lacework CLI. For more information, see the [container vulnerability section in the Lacework CLI +documentation](https://github.com/lacework/go-sdk/wiki/CLI-Documentation#container-vulnerability-assessments). This resource has two authentication methods: * AWS Access Key-Based Authentication * AWS IAM Role-Based Authentication +!> **Warning:** It is possible to switch authentication methods but the resource +will be destroyed and recreated. + For more information, see [Integrate Amazon Container Registry documentation](https://support.lacework.com/hc/en-us/articles/360048500133-Integrate-Amazon-Container-Registry) ## Example Usage @@ -26,7 +32,7 @@ For more information, see [Integrate Amazon Container Registry documentation](ht ### Authentication via AWS Access Key ```hcl resource "lacework_integration_ecr" "access_key" { - name = "ERC Example" + name = "ECR using Access Keys" registry_domain = "YourAWSAccount.dkr.ecr.YourRegion.amazonaws.com" credentials { access_key_id = "AWS123abcAccessKeyID" @@ -38,7 +44,7 @@ resource "lacework_integration_ecr" "access_key" { ### Authentication via AWS IAM Role ```hcl resource "lacework_integration_ecr" "iam_role" { - name = "ERC Example" + name = "ECR using IAM Role" registry_domain = "YourAWSAccount.dkr.ecr.YourRegion.amazonaws.com" credentials { role_arn = "arn:aws:iam::1234567890:role/lacework_iam_example_role"