Skip to content

Commit 344a038

Browse files
Merge pull request #70 from NHSDigital/feature/CCM-8197_Cross_Account_Observability
CCM-8197: Cross Account Observability
2 parents 3ccec8c + 3a86589 commit 344a038

7 files changed

Lines changed: 261 additions & 0 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!-- BEGIN_TF_DOCS -->
2+
<!-- markdownlint-disable -->
3+
<!-- vale off -->
4+
5+
## Requirements
6+
7+
| Name | Version |
8+
|------|---------|
9+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.0 |
10+
## Inputs
11+
12+
| Name | Description | Type | Default | Required |
13+
|------|-------------|------|---------|:--------:|
14+
| <a name="input_aws_account_id"></a> [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes |
15+
| <a name="input_component"></a> [component](#input\_component) | The name of the terraformscaffold component calling this module | `string` | n/a | yes |
16+
| <a name="input_default_tags"></a> [default\_tags](#input\_default\_tags) | Default tag map for application to all taggable resources in the module | `map(string)` | `{}` | no |
17+
| <a name="input_environment"></a> [environment](#input\_environment) | The name of the terraformscaffold environment the module is called for | `string` | n/a | yes |
18+
| <a name="input_log_group_configuration"></a> [log\_group\_configuration](#input\_log\_group\_configuration) | Configuration for filtering log groups in the link configuration. | <pre>object({<br/> filter = string<br/> })</pre> | `null` | no |
19+
| <a name="input_metric_configuration"></a> [metric\_configuration](#input\_metric\_configuration) | Configuration for filtering metrics in the link configuration. | <pre>object({<br/> filter = string<br/> })</pre> | `null` | no |
20+
| <a name="input_name"></a> [name](#input\_name) | A unique name to distinguish this module invocation from others within the same CSI scope | `string` | n/a | yes |
21+
| <a name="input_oam_sink_id"></a> [oam\_sink\_id](#input\_oam\_sink\_id) | The ID of the Cloudwatch OAM sink in the appropriate observability account. | `string` | `""` | no |
22+
| <a name="input_observability_account_id"></a> [observability\_account\_id](#input\_observability\_account\_id) | The Observability Account ID that needs access | `string` | n/a | yes |
23+
| <a name="input_project"></a> [project](#input\_project) | The name of the terraformscaffold project calling the module | `string` | n/a | yes |
24+
| <a name="input_region"></a> [region](#input\_region) | The AWS Region | `string` | n/a | yes |
25+
| <a name="input_resource_types"></a> [resource\_types](#input\_resource\_types) | The resource types to include in the OAM link. | `list(string)` | <pre>[<br/> "AWS::CloudWatch::Metric",<br/> "AWS::Logs::LogGroup"<br/>]</pre> | no |
26+
## Modules
27+
28+
No modules.
29+
## Outputs
30+
31+
| Name | Description |
32+
|------|-------------|
33+
| <a name="output_log_subscription_role_arn"></a> [log\_subscription\_role\_arn](#output\_log\_subscription\_role\_arn) | The ARN of the log subscription IAM role. |
34+
<!-- vale on -->
35+
<!-- markdownlint-enable -->
36+
<!-- END_TF_DOCS -->
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
resource "aws_iam_role" "log_subscription_role" {
2+
name = "${local.csi}-log-subscription-role"
3+
4+
assume_role_policy = jsonencode({
5+
Version = "2012-10-17"
6+
Statement = [
7+
{
8+
Effect = "Allow"
9+
Principal = {
10+
Service = "logs.${var.region}.amazonaws.com"
11+
}
12+
Action = "sts:AssumeRole"
13+
}
14+
]
15+
})
16+
}
17+
18+
resource "aws_iam_policy" "log_subscription_policy" {
19+
name = "${local.csi}-log-subscription-policy"
20+
description = "Policy for log subscription to send logs to the destination"
21+
22+
policy = jsonencode({
23+
Version = "2012-10-17"
24+
Statement = [
25+
{
26+
Effect = "Allow"
27+
Action = [
28+
"logs:PutSubscriptionFilter",
29+
"logs:DescribeLogGroups",
30+
"logs:DescribeLogStreams",
31+
"logs:PutLogEvents"
32+
]
33+
Resource = "arn:aws:logs:${var.region}:${var.observability_account_id}:destination:nhs-notify-main-acct-firehose-logs"
34+
}
35+
]
36+
})
37+
}
38+
39+
resource "aws_iam_role_policy_attachment" "log_subscription_policy_attachment" {
40+
role = aws_iam_role.log_subscription_role.name
41+
policy_arn = aws_iam_policy.log_subscription_policy.arn
42+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
locals {
2+
module = "obs-datasource"
3+
4+
csi = replace(
5+
format(
6+
"%s-%s-%s-%s",
7+
var.project,
8+
var.environment,
9+
var.component,
10+
var.name,
11+
),
12+
"_",
13+
"",
14+
)
15+
default_tags = merge(
16+
var.default_tags,
17+
{
18+
Module = local.module
19+
Name = local.csi
20+
},
21+
)
22+
23+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
resource "aws_oam_link" "cross_account_obs" {
2+
label_template = "$AccountName"
3+
resource_types = var.resource_types
4+
sink_identifier = "arn:aws:oam:${var.region}:${var.observability_account_id}:sink/${var.oam_sink_id}"
5+
tags = var.default_tags
6+
7+
link_configuration {
8+
dynamic "log_group_configuration" {
9+
for_each = var.log_group_configuration != null ? [var.log_group_configuration] : []
10+
content {
11+
filter = log_group_configuration.value.filter
12+
}
13+
}
14+
15+
dynamic "metric_configuration" {
16+
for_each = var.metric_configuration != null ? [var.metric_configuration] : []
17+
content {
18+
filter = metric_configuration.value.filter
19+
}
20+
}
21+
}
22+
}
23+
24+
data "aws_iam_policy" "cloudwatch_read_only" {
25+
name = "CloudWatchReadOnlyAccess"
26+
}
27+
28+
data "aws_iam_policy" "cloudwatch_automatic_dashboards" {
29+
name = "CloudWatchAutomaticDashboardsAccess"
30+
}
31+
32+
data "aws_iam_policy" "aws_xray_read_only" {
33+
name = "AWSXrayReadOnlyAccess"
34+
}
35+
36+
data "aws_iam_policy_document" "cross_account_obs_assume_role_policy" {
37+
statement {
38+
effect = "Allow"
39+
principals {
40+
type = "AWS"
41+
identifiers = [var.observability_account_id]
42+
}
43+
actions = ["sts:AssumeRole"]
44+
}
45+
}
46+
47+
resource "aws_iam_role" "cross_account_obs_role" {
48+
name = "CloudWatch-CrossAccountSharingRole"
49+
assume_role_policy = data.aws_iam_policy_document.cross_account_obs_assume_role_policy.json
50+
}
51+
52+
resource "aws_iam_role_policy_attachment" "cloudwatch_read_only_attachment" {
53+
policy_arn = data.aws_iam_policy.cloudwatch_read_only.arn
54+
role = aws_iam_role.cross_account_obs_role.name
55+
}
56+
57+
resource "aws_iam_role_policy_attachment" "cloudwatch_automatic_dashboards_attachment" {
58+
policy_arn = data.aws_iam_policy.cloudwatch_automatic_dashboards.arn
59+
role = aws_iam_role.cross_account_obs_role.name
60+
}
61+
62+
resource "aws_iam_role_policy_attachment" "aws_xray_read_only_attachment" {
63+
policy_arn = data.aws_iam_policy.aws_xray_read_only.arn
64+
role = aws_iam_role.cross_account_obs_role.name
65+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
output "log_subscription_role_arn" {
2+
description = "The ARN of the log subscription IAM role."
3+
value = aws_iam_role.log_subscription_role.arn
4+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
##
2+
# Basic inherited variables for terraformscaffold modules
3+
##
4+
5+
variable "project" {
6+
type = string
7+
description = "The name of the terraformscaffold project calling the module"
8+
}
9+
10+
variable "environment" {
11+
type = string
12+
description = "The name of the terraformscaffold environment the module is called for"
13+
}
14+
15+
variable "component" {
16+
type = string
17+
description = "The name of the terraformscaffold component calling this module"
18+
}
19+
20+
variable "aws_account_id" {
21+
type = string
22+
description = "The AWS Account ID (numeric)"
23+
}
24+
25+
##
26+
# Variable specific to the module
27+
##
28+
29+
# We presume this will always be specified. The default of {} will cause an error if a valid map is not specified.
30+
# If we ever want to define this but allow it to not be specified, then we must provide a default tag keypair will be applied
31+
# as the true default. In any other case default_tags should be removed from the module.
32+
variable "default_tags" {
33+
type = map(string)
34+
description = "Default tag map for application to all taggable resources in the module"
35+
default = {}
36+
}
37+
38+
variable "region" {
39+
type = string
40+
description = "The AWS Region"
41+
}
42+
43+
variable "name" {
44+
type = string
45+
description = "A unique name to distinguish this module invocation from others within the same CSI scope"
46+
}
47+
48+
variable "oam_sink_id" {
49+
description = "The ID of the Cloudwatch OAM sink in the appropriate observability account."
50+
type = string
51+
default = ""
52+
}
53+
54+
variable "observability_account_id" {
55+
type = string
56+
description = "The Observability Account ID that needs access"
57+
}
58+
59+
variable "log_group_configuration" {
60+
description = "Configuration for filtering log groups in the link configuration." # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/oam_link#link_configuration-block
61+
type = object({
62+
filter = string
63+
})
64+
default = null
65+
}
66+
67+
variable "metric_configuration" {
68+
description = "Configuration for filtering metrics in the link configuration." # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/oam_link#link_configuration-block
69+
type = object({
70+
filter = string
71+
})
72+
default = null
73+
}
74+
75+
variable "resource_types" {
76+
type = list(string)
77+
description = "The resource types to include in the OAM link."
78+
default = [
79+
"AWS::CloudWatch::Metric",
80+
"AWS::Logs::LogGroup"
81+
]
82+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
terraform {
3+
required_providers {
4+
aws = {
5+
source = "hashicorp/aws"
6+
}
7+
}
8+
required_version = ">= 1.9.0"
9+
}

0 commit comments

Comments
 (0)