Skip to content

Commit

Permalink
Add assume role authentication for CloudWatch metrics integration (#208)
Browse files Browse the repository at this point in the history
Adds an additional authentication method for CloudWatch metrics integration. Now support both AWS access key and IAM role.
  • Loading branch information
tbroden84 authored Jun 12, 2023
1 parent 37853e2 commit 4ecd90c
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 73 deletions.
131 changes: 62 additions & 69 deletions cloudamqp/resource_cloudamqp_integration_metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ func resourceIntegrationMetric() *schema.Resource {
Sensitive: true,
Description: "AWS secret key. (Cloudwatch)",
},
"iam_role": {
Type: schema.TypeString,
Optional: true,
Description: "The ARN of the role to be assumed when publishing metrics. (Cloudwatch)",
},
"iam_external_id": {
Type: schema.TypeString,
Optional: true,
Description: "External identifier that match the role you created. (Cloudwatch)",
},
"api_key": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -137,7 +147,7 @@ func resourceIntegrationMetricCreate(d *schema.ResourceData, meta interface{}) e
api = meta.(*api.API)
intName = strings.ToLower(d.Get("name").(string))
commonKeys = []string{"tags", "queue_allowlist", "vhost_allowlist"}
keys = integrationMetricKeys(commonKeys, intName)
keys = integrationMetricKeys(intName)
params = make(map[string]interface{})
)

Expand All @@ -150,41 +160,36 @@ func resourceIntegrationMetricCreate(d *schema.ResourceData, meta interface{}) e
var jsonMap map[string]interface{}
json.Unmarshal([]byte(uDec), &jsonMap)
for _, k := range keys {
if contains(commonKeys, k) {
v := d.Get(k)
if v == "" || v == nil {
delete(params, k)
continue
} else if k == "queue_allowlist" {
k = "queue_regex"
} else if k == "vhost_allowlist" {
k = "vhost_regex"
}
params[k] = v
} else {
params[k] = jsonMap[k]
}
params[k] = jsonMap[k]
}
} else {
for _, k := range keys {
v := d.Get(k)
if contains(commonKeys, k) && v == "" {
delete(params, k)
if v == "" || v == nil {
continue
} else if k == "queue_allowlist" {
k = "queue_regex"
} else if k == "vhost_allowlist" {
k = "vhost_regex"
}

if v != nil {
} else {
params[k] = v
}
}
}

data, err := api.CreateIntegration(d.Get("instance_id").(int), "metrics", intName, params)
// Add commons keys if present
for _, k := range commonKeys {
v := d.Get(k)
if k == "queue_allowlist" {
k = "queue_regex"
} else if k == "vhost_allowlist" {
k = "vhost_regex"
}

if v == "" || v == nil {
continue
} else {
params[k] = v
}
}

data, err := api.CreateIntegration(d.Get("instance_id").(int), "metrics", intName, params)
if err != nil {
return err
}
Expand Down Expand Up @@ -237,7 +242,7 @@ func resourceIntegrationMetricUpdate(d *schema.ResourceData, meta interface{}) e
api = meta.(*api.API)
intName = strings.ToLower(d.Get("name").(string))
commonKeys = []string{"tags", "queue_allowlist", "vhost_allowlist"}
keys = integrationMetricKeys(commonKeys, intName)
keys = integrationMetricKeys(intName)
params = make(map[string]interface{})
)

Expand All @@ -250,39 +255,35 @@ func resourceIntegrationMetricUpdate(d *schema.ResourceData, meta interface{}) e
var jsonMap map[string]interface{}
json.Unmarshal([]byte(uDec), &jsonMap)
for _, k := range keys {
if contains(commonKeys, k) {
v := d.Get(k)
if v == "" || v == nil {
delete(params, k)
continue
} else if k == "queue_allowlist" {
k = "queue_regex"
} else if k == "vhost_allowlist" {
k = "vhost_regex"
}
params[k] = v
} else {
params[k] = jsonMap[k]
}
params[k] = jsonMap[k]
}
} else {
for _, k := range keys {
v := d.Get(k)
if contains(commonKeys, k) && v == "" {
delete(params, k)
if v == "" || v == nil {
continue
} else if k == "queue_allowlist" {
k = "queue_regex"
} else if k == "vhost_allowlist" {
k = "vhost_regex"
}

if v != nil {
} else {
params[k] = v
}
}
}

// Add commons keys if present
for _, k := range commonKeys {
v := d.Get(k)
if k == "queue_allowlist" {
k = "queue_regex"
} else if k == "vhost_allowlist" {
k = "vhost_regex"
}

if v == "" || v == nil {
continue
} else {
params[k] = v
}
}

err := api.UpdateIntegration(d.Get("instance_id").(int), "metrics", d.Id(), params)
if err != nil {
return err
Expand Down Expand Up @@ -314,6 +315,8 @@ func validateIntegrationMetricSchemaAttribute(key string) bool {
case "region",
"access_key_id",
"secret_access_key",
"iam_role",
"iam_external_id",
"tags",
"queue_regex",
"vhost_regex",
Expand All @@ -330,35 +333,25 @@ func validateIntegrationMetricSchemaAttribute(key string) bool {
}
}

func integrationMetricKeys(commonKeys []string, intName string) []string {
keys := commonKeys
func integrationMetricKeys(intName string) []string {
switch intName {
case "cloudwatch":
return append(keys, "region", "access_key_id", "secret_access_key")
return []string{"region", "access_key_id", "secret_access_key", "iam_role", "iam_external_id"}
case "cloudwatch_v2":
return append(keys, "region", "access_key_id", "secret_access_key")
return []string{"region", "access_key_id", "secret_access_key", "iam_role", "iam_external_id"}
case "librato":
return append(keys, "email", "api_key")
return []string{"email", "api_key"}
case "datadog":
return append(keys, "api_key", "region")
return []string{"api_key", "region"}
case "datadog_v2":
return append(keys, "api_key", "region")
return []string{"api_key", "region"}
case "newrelic":
return append(keys, "license_key")
return []string{"license_key"}
case "newrelic_v2":
return append(keys, "api_key", "region")
return []string{"api_key", "region"}
case "stackdriver":
return append(keys, "client_email", "private_key_id", "private_key", "project_id")
return []string{"client_email", "private_key_id", "private_key", "project_id"}
default:
return append(keys, "region", "access_keys", "secret_access_keys", "email", "api_key", "license_key")
}
}

func contains(s []string, searchString string) bool {
for i := range s {
if searchString == s[i] {
return true
}
return []string{"region", "access_keys", "secret_access_keys", "email", "api_key", "license_key"}
}
return false
}
37 changes: 33 additions & 4 deletions docs/resources/integration_metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Only available for dedicated subscription plans.
</b>
</summary>

***Access key***
```hcl
resource "cloudamqp_integration_metric" "cloudwatch" {
instance_id = cloudamqp_instance.instance.id
Expand All @@ -37,6 +38,28 @@ resource "cloudamqp_integration_metric" "cloudwatch_v2" {
region = var.aws_region
}
```

***Assume role***
```hcl
resource "cloudamqp_integration_metric" "cloudwatch" {
instance_id = cloudamqp_instance.instance.id
name = "cloudwatch"
iam_role = var.aws_iam_role
iam_external_id = var.external_id
region = var.aws_region
}
resource "cloudamqp_integration_metric" "cloudwatch_v2" {
instance_id = cloudamqp_instance.instance.id
name = "cloudwatch_v2"
iam_role = var.aws_iam_role
iam_external_id = var.external_id
region = var.aws_region
}
```

* AWS IAM role: arn:aws:iam::ACCOUNT-ID:role/ROLE-NAME
* External id: Create own external identifier that match the role created. E.g. "cloudamqp-abc123".
</details>

<details>
Expand Down Expand Up @@ -197,6 +220,8 @@ The following arguments are supported:
* `region` - (Optional) Region hosting the integration service.
* `access_key_id` - (Optional) AWS access key identifier.
* `secret_access_key` - (Optional) AWS secret access key.
* `iam_role` - (Optional) The ARN of the role to be assumed when publishing metrics.
* `iam_external_id` - (Optional) External identifier that match the role you created.
* `api_key` - (Optional) The API key for the integration service.
* `email` - (Optional) The email address registred for the integration service.
* `credentials` - (Optional) Google Service Account private key credentials.
Expand All @@ -217,8 +242,10 @@ Valid names for third party log integration.

| Name | Description |
|---------------|---------------------------------------------------------------|
| cloudwatch | Create an IAM with programmatic access. |
| cloudwatch_v2 | Create an IAM with programmatic access. |
| cloudwatch | Access key: Create an IAM user with permission to `PutMetricData` |
| cloudwatch_v2 | Access key: Create an IAM user with permission to `PutMetricData` |
| cloudwatch | Assume role: Create a IAM role with the permission to `PutMetricData` |
| cloudwatch_v2 | Assume role: Create a IAM role with the permission to `PutMetricData` |
| datadog | Create a Datadog API key at app.datadoghq.com |
| datadog_v2 | Create a Datadog API key at app.datadoghq.com |
| librato | Create a new API token (with record only permissions) here: https://metrics.librato.com/tokens |
Expand All @@ -235,8 +262,10 @@ Optional arguments for all integrations: *tags*, *queue_allowlist*, *vhost_allow

| Name | Type | Required arguments |
| ---- | ---- | ---- |
| Cloudwatch | cloudwatch | region, access_key_id, secret_access_key |
| Cloudwatch v2 | cloudwatch_v2 | region, access_key_id, secret_access_key |
| Cloudwatch | cloudwatch | Access key: region, access_key_id, secret_access_key |
| Cloudwatch v2 | cloudwatch_v2 | Access key: region, access_key_id, secret_access_key |
| Cloudwatch | cloudwatch | Assume role: region, iam_role, iam_external_id |
| Cloudwatch v2 | cloudwatch_v2 | Assume role: region, iam_role, iam_external_id |
| Datadog | datadog | api_key, region |
| Datadog v2 | datadog_v2 | api_key, region |
| Librato | librato | email, api_key |
Expand Down

0 comments on commit 4ecd90c

Please sign in to comment.