Skip to content

Commit 5eb5b89

Browse files
authored
Merge pull request #2 from appvia/create-role
feat: implementation
2 parents 91b1ef1 + d63097a commit 5eb5b89

File tree

8 files changed

+180
-29
lines changed

8 files changed

+180
-29
lines changed

.terraform.lock.hcl

-25
This file was deleted.

README.md

+18-3
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,37 @@ The `terraform-docs` utility is used to generate this README. Follow the below s
3434
|------|---------|
3535
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.7 |
3636
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.0.0 |
37+
| <a name="requirement_time"></a> [time](#requirement\_time) | >= 0.12.0 |
3738

3839
## Providers
3940

40-
No providers.
41+
| Name | Version |
42+
|------|---------|
43+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.0.0 |
44+
| <a name="provider_time"></a> [time](#provider\_time) | >= 0.12.0 |
4145

4246
## Modules
4347

4448
No modules.
4549

4650
## Resources
4751

48-
No resources.
52+
| Name | Type |
53+
|------|------|
54+
| [aws_cloudformation_stack.management](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack) | resource |
55+
| [aws_cloudformation_stack_set.member_accounts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack_set) | resource |
56+
| [aws_cloudformation_stack_set_instance.member_accounts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack_set_instance) | resource |
57+
| [time_offset.expiry](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/offset) | resource |
58+
| [aws_organizations_organization.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source |
4959

5060
## Inputs
5161

52-
No inputs.
62+
| Name | Description | Type | Default | Required |
63+
|------|-------------|------|---------|:--------:|
64+
| <a name="input_deployment_account_ids"></a> [deployment\_account\_ids](#input\_deployment\_account\_ids) | List of account IDs in which to deploy the remote audit access role | `list(string)` | n/a | yes |
65+
| <a name="input_external_id"></a> [external\_id](#input\_external\_id) | External ID should be a string of cryptographically safe random characters | `string` | n/a | yes |
66+
| <a name="input_appvia_role_arn"></a> [appvia\_role\_arn](#input\_appvia\_role\_arn) | Allows specifying a non-standard IAM role. Only set this if asked to do so by Appvia | `string` | `"arn:aws:iam::730335310409:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_WAFSupport_19c9bc61106389c3"` | no |
67+
| <a name="input_expiry_days"></a> [expiry\_days](#input\_expiry\_days) | The number of days the role is available before access will be denied | `number` | `14` | no |
5368

5469
## Outputs
5570

cloud_formation/role.yaml

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
3+
Parameters:
4+
AppviaRoleARN:
5+
Type: String
6+
Description: Fully-qualified ARN of the remote role
7+
Default: arn:aws:iam::730335310409:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_WAFSupport_19c9bc61106389c3
8+
ExternalID:
9+
Type: String
10+
Description: External ID shared between consumer and Appvia
11+
ExpiryDate:
12+
Type: String
13+
14+
Resources:
15+
Role:
16+
Type: AWS::IAM::Role
17+
Properties:
18+
RoleName: AppviaAuditRole
19+
Path: /
20+
AssumeRolePolicyDocument:
21+
Version: '2012-10-17'
22+
Statement:
23+
- Effect: Allow
24+
Principal:
25+
AWS:
26+
- !Ref AppviaRoleARN
27+
Action:
28+
- sts:AssumeRole
29+
Condition:
30+
StringEquals:
31+
"sts:ExternalId": !Ref ExternalID
32+
ManagedPolicyArns:
33+
- arn:aws:iam::aws:policy/SecurityAudit
34+
- arn:aws:iam::aws:policy/ReadOnlyAccess
35+
Policies:
36+
- PolicyName: PermissionDeadline
37+
PolicyDocument:
38+
Version: '2012-10-17'
39+
Statement:
40+
- Effect: Deny
41+
Action: '*'
42+
Resource: '*'
43+
Condition:
44+
DateGreaterThan:
45+
"aws:CurrentTime": !Ref ExpiryDate

data.tf

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data "aws_organizations_organization" "current" {}

locals.tf

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
locals {
2+
# CloudFormation template
3+
template_body = file("${path.module}/cloud_formation/role.yaml")
4+
5+
# Lookup the management account ID from org data
6+
management_account_id = data.aws_organizations_organization.current.master_account_id
7+
8+
# Member accounts are any provided accounts that are not the management account
9+
member_account_ids = [
10+
for v in var.deployment_account_ids : v if v != local.management_account_id
11+
]
12+
13+
# If the management account is in the list, this evaluates to true
14+
deploy_to_management = contains(var.deployment_account_ids, local.management_account_id)
15+
}

main.tf

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
resource "time_offset" "expiry" {
2+
offset_days = var.expiry_days
3+
}
4+
5+
resource "aws_cloudformation_stack" "management" {
6+
count = local.deploy_to_management ? 1 : 0
7+
8+
name = "AppviaAuditRole"
9+
template_body = local.template_body
10+
on_failure = "ROLLBACK"
11+
12+
capabilities = [
13+
"CAPABILITY_NAMED_IAM",
14+
"CAPABILITY_AUTO_EXPAND",
15+
"CAPABILITY_IAM",
16+
]
17+
18+
parameters = {
19+
AppviaRoleARN = var.appvia_role_arn
20+
ExternalID = var.external_id
21+
ExpiryDate = time_offset.expiry.rfc3339
22+
}
23+
24+
lifecycle {
25+
ignore_changes = [
26+
capabilities,
27+
]
28+
}
29+
}
30+
31+
resource "aws_cloudformation_stack_set" "member_accounts" {
32+
name = "AppviaAuditRole"
33+
description = "Provisions federated IAM role allowing Appvia remote audit access"
34+
template_body = local.template_body
35+
permission_model = "SERVICE_MANAGED"
36+
37+
capabilities = [
38+
"CAPABILITY_NAMED_IAM",
39+
"CAPABILITY_AUTO_EXPAND",
40+
"CAPABILITY_IAM",
41+
]
42+
43+
parameters = {
44+
AppviaRoleARN = var.appvia_role_arn
45+
ExternalID = var.external_id
46+
ExpiryDate = time_offset.expiry.rfc3339
47+
}
48+
49+
auto_deployment {
50+
enabled = true
51+
retain_stacks_on_account_removal = false
52+
}
53+
54+
lifecycle {
55+
ignore_changes = [
56+
administration_role_arn,
57+
capabilities,
58+
]
59+
}
60+
}
61+
62+
resource "aws_cloudformation_stack_set_instance" "member_accounts" {
63+
count = length(var.deployment_account_ids) > 0 ? 1 : 0
64+
65+
stack_set_name = aws_cloudformation_stack_set.member_accounts.name
66+
67+
deployment_targets {
68+
account_filter_type = "INTERSECTION"
69+
accounts = local.member_account_ids
70+
71+
organizational_unit_ids = [
72+
data.aws_organizations_organization.current.roots[0].id,
73+
]
74+
}
75+
}

terraform.tf

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
terraform {
32
required_version = ">= 1.0.7"
43

@@ -8,5 +7,10 @@ terraform {
87
source = "hashicorp/aws"
98
version = ">= 5.0.0"
109
}
10+
11+
time = {
12+
source = "hashicorp/time"
13+
version = ">= 0.12.0"
14+
}
1115
}
1216
}

variables.tf

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
variable "appvia_role_arn" {
2+
type = string
3+
default = "arn:aws:iam::730335310409:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_WAFSupport_19c9bc61106389c3"
4+
description = "Allows specifying a non-standard IAM role. Only set this if asked to do so by Appvia"
5+
}
6+
7+
variable "deployment_account_ids" {
8+
type = list(string)
9+
description = "List of account IDs in which to deploy the remote audit access role"
10+
}
11+
12+
variable "external_id" {
13+
type = string
14+
description = "External ID should be a string of cryptographically safe random characters"
15+
}
16+
17+
variable "expiry_days" {
18+
type = number
19+
default = 14
20+
description = "The number of days the role is available before access will be denied"
21+
}

0 commit comments

Comments
 (0)