adding subaccount module
parent
ea7a2b2174
commit
1c37cbe254
@ -0,0 +1,51 @@
|
||||
# aws-master - accounts
|
||||
|
||||
This module sets up a subordinate AWS account under a given organization. You need to use it in conjunction with the `aws-master/organizations` module to setup the Organizations backend on a master payer account.
|
||||
|
||||
Only use this module on the "Master Payer" AWS account.
|
||||
|
||||
*This has not been tested yet and will not work*.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
module "master_payer" {
|
||||
source = "github.com/lalanza808/tf-modules.git/organizations/suborganizations"
|
||||
|
||||
prefix = module.labels.id
|
||||
tags = module.labels.tags
|
||||
|
||||
enable_cur = true # cost and usage reporting to S3
|
||||
enable_org = true # enables organizations service
|
||||
}
|
||||
|
||||
module "aws_account_sandbox" "sandbox" {
|
||||
source = "github.com/lalanza808/tf-modules.git/organizations/subaccounts"
|
||||
|
||||
account_name = "sandbox"
|
||||
account_email = "aws-admin+sandbox@corp.com"
|
||||
parent_ou_id = module.master_payer.prod_ou_id
|
||||
}
|
||||
|
||||
output "sandbox_account_id" {
|
||||
value = module.aws_account_sandbox.sandbox.account_id
|
||||
}
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
|
||||
You need to specify the following:
|
||||
|
||||
* `parent_ou_id`
|
||||
* `account_name`
|
||||
* `account_email`
|
||||
|
||||
See the full list of inputs here: [variables.tf](./variables.tf)
|
||||
|
||||
## Outputs
|
||||
|
||||
* `account_id`
|
||||
* `account_arn`
|
||||
|
||||
[output.tf](./output.tf)
|
@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script initializes newly created AWS accounts with a Cloudformation init template.
|
||||
# It is executed by a null_resource and should only trigger once per account.
|
||||
|
||||
# Don't echo commands and error on any issues with auth/assume role
|
||||
set +x
|
||||
set -e
|
||||
|
||||
# Wait a bit before proceeding - the script will invoke right after the account is created but sometimes takes a few seconds
|
||||
sleep 30
|
||||
|
||||
# Assume a role into the Master AWS account
|
||||
TEMPCREDS=$(aws sts assume-role --duration-seconds 900 \
|
||||
--role-arn arn:aws:iam::${MASTER_ACCOUNT_ID}:role/${MASTER_ACCOUNT_ROLE} \
|
||||
--role-session-name terraform-auto-account-provisioning)
|
||||
export AWS_ACCESS_KEY_ID=$(echo $TEMPCREDS | jq -r '.Credentials.AccessKeyId')
|
||||
export AWS_SECRET_ACCESS_KEY=$(echo $TEMPCREDS | jq -r '.Credentials.SecretAccessKey')
|
||||
export AWS_SESSION_TOKEN=$(echo $TEMPCREDS | jq -r '.Credentials.SessionToken')
|
||||
|
||||
# Assume another role through the Master into the newly provisioned account
|
||||
TEMPCREDS=$(aws sts assume-role --duration-seconds 900 \
|
||||
--role-arn arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME} \
|
||||
--role-session-name terraform-auto-account-provisioning)
|
||||
export AWS_ACCESS_KEY_ID=$(echo $TEMPCREDS | jq -r '.Credentials.AccessKeyId')
|
||||
export AWS_SECRET_ACCESS_KEY=$(echo $TEMPCREDS | jq -r '.Credentials.SecretAccessKey')
|
||||
export AWS_SESSION_TOKEN=$(echo $TEMPCREDS | jq -r '.Credentials.SessionToken')
|
||||
|
||||
set -x
|
||||
# Now echo commands and don't error because for some reason 0> codes can be expected with `aws cloudformation deploy`
|
||||
set +e
|
||||
|
||||
# Deploy a Cloudformation stack to the new account to initialize the access roles
|
||||
aws cloudformation deploy \
|
||||
--stack-name "${STACK_NAME}" \
|
||||
--template-file "${FILE_PATH}" \
|
||||
--parameter-overrides "Account=${ACCOUNT_NAME}" \
|
||||
--capabilities "CAPABILITY_NAMED_IAM" \
|
||||
--region "${REGION}"
|
||||
|
||||
exit 0
|
@ -0,0 +1,82 @@
|
||||
---
|
||||
AWSTemplateFormatVersion: "2010-09-09"
|
||||
|
||||
Description: This stack creates the required resources for cross account management.
|
||||
|
||||
Parameters:
|
||||
Prefix:
|
||||
Type: String
|
||||
Description: "The string to prefix in front of created resources"
|
||||
Default: "organizations"
|
||||
Account:
|
||||
Type: String
|
||||
Description: "The name of the account - dev, test, stage, prod, mgmt, etc"
|
||||
|
||||
Resources:
|
||||
# IAM
|
||||
ManagementRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: ManagementRole
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
AWS:
|
||||
- arn:aws:iam::${AWS::AccountId}:role/OrganizationAccountAccessRole
|
||||
Action: sts:AssumeRole
|
||||
ManagedPolicyArns:
|
||||
- arn:aws:iam::aws:policy/AdministratorAccess
|
||||
|
||||
# Terraform Backend
|
||||
TerraformStateBucket:
|
||||
Type: AWS::S3::Bucket
|
||||
Properties:
|
||||
AccessControl: Private
|
||||
BucketEncryption:
|
||||
ServerSideEncryptionConfiguration:
|
||||
- ServerSideEncryptionByDefault:
|
||||
SSEAlgorithm: AES256
|
||||
BucketName: !Sub ${Prefix}-${Account}-terraform-state
|
||||
VersioningConfiguration:
|
||||
Status: Enabled
|
||||
TerraformStateBucketPolicy:
|
||||
Type: AWS::S3::BucketPolicy
|
||||
Properties:
|
||||
Bucket: !Ref TerraformStateBucket
|
||||
PolicyDocument:
|
||||
Statement:
|
||||
- Action: s3:*
|
||||
Effect: Allow
|
||||
Principal:
|
||||
AWS: arn:aws:iam::000000000000:role/RemoteAccess
|
||||
Resource:
|
||||
- !GetAtt TerraformStateBucket.Arn
|
||||
- !Join
|
||||
- '/'
|
||||
- - !GetAtt TerraformStateBucket.Arn
|
||||
- '*'
|
||||
TerraformStateTable:
|
||||
Type: AWS::DynamoDB::Table
|
||||
Properties:
|
||||
AttributeDefinitions:
|
||||
- AttributeName: LockID
|
||||
AttributeType: S
|
||||
KeySchema:
|
||||
- AttributeName: LockID
|
||||
KeyType: HASH
|
||||
ProvisionedThroughput:
|
||||
ReadCapacityUnits: 5
|
||||
WriteCapacityUnits: 5
|
||||
TableName: !Sub ${Prefix}-${Account}-terraform-locks
|
||||
|
||||
Outputs:
|
||||
TerraformStateBucketOutput:
|
||||
Description: Bucket used to store Terraform remote state file
|
||||
Value: !Ref TerraformStateBucket
|
||||
TerraformStateTableOutput:
|
||||
Description: DynamoDB table used for Terraform state locking functionality
|
||||
Value: !Ref TerraformStateTable
|
||||
ManagementRoleArn:
|
||||
Value: !GetAtt ManagementRole.Arn
|
@ -0,0 +1,43 @@
|
||||
locals {
|
||||
cft_file = "${path.module}/files/init.yaml"
|
||||
cft_script = "${path.module}/files/account_init.sh"
|
||||
}
|
||||
|
||||
data "local_file" "init_cft" {
|
||||
filename = local.cft_file
|
||||
}
|
||||
|
||||
resource "aws_organizations_account" "this" {
|
||||
name = var.account_name
|
||||
email = var.account_email
|
||||
iam_user_access_to_billing = var.iam_billing_access
|
||||
parent_id = var.parent_ou_id
|
||||
role_name = var.access_role_name
|
||||
tags = var.tags
|
||||
|
||||
# There is no AWS Organizations API for reading role_name
|
||||
lifecycle {
|
||||
ignore_changes = ["role_name"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "null_resource" "initialize" {
|
||||
triggers = {
|
||||
file_content = data.local_file.init_cft.content_base64
|
||||
}
|
||||
|
||||
provisioner "local-exec" {
|
||||
command = local.cft_script
|
||||
|
||||
environment = {
|
||||
STACK_NAME = var.init_stack_name
|
||||
FILE_PATH = local.cft_file
|
||||
REGION = var.init_stack_region
|
||||
ACCOUNT_ID = aws_organizations_account.this.id
|
||||
ROLE_NAME = var.access_role_name
|
||||
ACCOUNT_NAME = var.account_name
|
||||
MASTER_ACCOUNT_ID = var.master_account_id
|
||||
MASTER_ACCOUNT_ROLE = var.master_account_role
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
output "account_id" {
|
||||
value = aws_organizations_account.this.id
|
||||
}
|
||||
|
||||
output "account_arn" {
|
||||
value = aws_organizations_account.this.arn
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
variable "iam_billing_access" {
|
||||
default = "ALLOW"
|
||||
}
|
||||
|
||||
variable "access_role_name" {
|
||||
default = "OrganizationAccountAccessRole"
|
||||
}
|
||||
|
||||
variable "master_account_id" {
|
||||
description = "Master AWS account ID where Organizations are provisioned"
|
||||
default = "0000000000"
|
||||
}
|
||||
|
||||
variable "master_account_role" {
|
||||
description = "Role to assume into Master AWS account"
|
||||
default = "ManagementAccess"
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
default = {}
|
||||
type = "map"
|
||||
}
|
||||
|
||||
variable "init_stack_name" {
|
||||
default = "organizations-account-init"
|
||||
description = "Name of the Cloudformation stack to use"
|
||||
}
|
||||
|
||||
variable "init_stack_region" {
|
||||
default = "us-east-1"
|
||||
description = "Region to deploy the Cloudformation init stack into"
|
||||
}
|
||||
|
||||
variable "parent_ou_id" {}
|
||||
variable "account_name" {}
|
||||
variable "account_email" {}
|
Loading…
Reference in New Issue