Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terragrunt config export #26

Merged
merged 4 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions terragrunt-config-export/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,30 @@ Add the following to your `bitbucket-pipelines.yml` file:
variables:
ECS_CLUSTER: 'my-ecs-cluster'
ECS_SERVICE: 'my-ecs-service'
AWS_OIDC_ROLE_ARN: 'arn:aws:iam::account-id:role/role-name'
# Optional variables
EXTRA_ENV: #Extra env vars to include in the config
BASE_URL: example.com
ENDPOINTS: ['authenticate']
IAM_ROLE: 'arn:aws:iam::account-id:role/role-name'
AWS_ROLE_ARN: 'arn:aws:iam::account-id:role/role-name'
AWS_PROFILE: 'staging'
OUTPUT_FILE: 'values.yml'
AWS_REGION: 'eu-west-1'
```

## Variables

| Variable | Usage | Required |
| -------- |---------------------------------------------| -------- |
| ECS_CLUSTER | Name of the ECS cluster | Yes |
| ECS_SERVICE | Name of the ECS service | Yes |
| EXTRA_ENV | Extra environment vars for the sevice | No |
| ENDPOINTS | Endpoints for the target groups | No |
| IAM_ROLE | IAM role for the service to use | No |
| AWS_ROLE_ARN | ARN of IAM role to assume to get the config | No |
| AWS_PROFILE | Profile to use to get the config | No |
| OUTPUT_FILE | File to write the config to | No |
| AWS_REGION | AWS region | No |
| Variable | Usage | Required |
| -------- |---------------------------------------| -------- |
| ECS_CLUSTER | Name of the ECS cluster | Yes |
| ECS_SERVICE | Name of the ECS service | Yes |
| AWS_OIDC_ROLE_ARN | OIDC Role to assume | Yes |
| EXTRA_ENV | Extra environment vars for the sevice | No |
| ENDPOINTS | Endpoints for the target groups | No |
| IAM_ROLE | IAM role for the service to use | No |
| AWS_PROFILE | Profile to use to get the config | No |
| OUTPUT_FILE | File to write the config to | No |
| AWS_REGION | AWS region | No |

## Examples

Expand All @@ -44,7 +44,7 @@ Add the following to your `bitbucket-pipelines.yml` file:
variables:
ECS_CLUSTER: 'my-ecs-cluster'
ECS_SERVICE: 'my-ecs-service'
AWS_ROLE_ARN: 'arn:aws:iam::account-id:role/role-name'
AWS_OIDC_ROLE_ARN: 'arn:aws:iam::account-id:role/role-name'
```

### Write output to a file and use in subsequent steps
Expand All @@ -57,7 +57,7 @@ Add the following to your `bitbucket-pipelines.yml` file:
variables:
ECS_CLUSTER: 'my-ecs-cluster'
ECS_SERVICE: 'my-ecs-service'
AWS_ROLE_ARN: 'arn:aws:iam::account-id:role/role-name'
AWS_OIDC_ROLE_ARN: 'arn:aws:iam::account-id:role/role-name'
OUTPUT_FILE: 'values.yml'
- cat values.yml.json
```
Expand Down
81 changes: 43 additions & 38 deletions terragrunt-config-export/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,50 @@
import sys
import boto3
import yaml
from datetime import datetime
import time
import stat
import configparser


def auth_oidc():
random_number = str(time.time_ns())
aws_config_directory = os.path.join(os.environ["HOME"], '.aws')
oidc_token_directory = os.path.join(aws_config_directory, '.aws-oidc')

os.makedirs(aws_config_directory, exist_ok=True)
os.makedirs(oidc_token_directory, exist_ok=True)

web_identity_token_path = os.path.join(oidc_token_directory, f'oidc_token_{random_number}')
with open(web_identity_token_path, 'w') as f:
f.write(os.getenv('BITBUCKET_STEP_OIDC_TOKEN'))

os.chmod(web_identity_token_path, mode=stat.S_IRUSR)
print('Web identity token file is created')

aws_configfile_path = os.path.join(aws_config_directory, 'config')
with open(aws_configfile_path, 'w') as configfile:
config = configparser.ConfigParser()
config['default'] = {
'role_arn': os.getenv('\fi'),
'web_identity_token_file': web_identity_token_path
}
config.write(configfile)
print('Configured settings for authentication with assume web identity role')

def get_boto3_client(service_name='ecs'):
"""
Create and return a boto3 client with appropriate authentication.
"""
region = os.environ.get('AWS_REGION', os.environ.get('AWS_DEFAULT_REGION', 'eu-west-1'))
profile_name = os.environ.get('AWS_PROFILE')
role_arn = os.environ.get('AWS_ROLE_ARN')

if role_arn:
# Create an STS client to assume the role
sts_client = boto3.client('sts', region_name=region)

# Assume the role
response = sts_client.assume_role(
RoleArn=role_arn,
RoleSessionName=f"ECSContainerDefinitionsPipe-{datetime.now().strftime('%Y%m%d%H%M%S')}"
)

# Extract temporary credentials
credentials = response['Credentials']
region = os.getenv('AWS_REGION', os.getenv('AWS_DEFAULT_REGION', 'eu-west-1'))
profile_name = os.getenv('AWS_PROFILE')
oidc = os.getenv('AWS_OIDC_ROLE_ARN')

# Create a new session with the assumed role credentials
return boto3.client(
service_name,
region_name=region,
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken']
)
if oidc:
auth_oidc()
return boto3.client(service_name,region_name=region)
elif profile_name:
# Use the specified AWS profile (including SSO profiles)
session = boto3.Session(profile_name=profile_name)
return session.client(service_name, region_name=region)
else:
# Standard credentials (from environment or instance profile)
return boto3.client(service_name, region_name=region)


def convert_to_terragrunt_format(task_definition, service_name):
"""
Expand All @@ -51,16 +56,16 @@ def convert_to_terragrunt_format(task_definition, service_name):
# Initialize the terragrunt config structure
config = {
"deployment": {
"extraEnv": os.environ.get('EXTRA_ENV', [])
"extraEnv": os.getenv('EXTRA_ENV', [])
},
"terragruntConfig": {
"name": f"({service_name})",
"secrets": [],
"containers": [],
"mainContainerName": "",
"resources": [],
"endpoints": os.environ.get('ENDPOINTS', []),
"iamRole": os.environ.get('IAM_ROLE', "")
"endpoints": os.getenv('ENDPOINTS', []),
"iamRole": os.getenv('IAM_ROLE', "")
}
}

Expand Down Expand Up @@ -121,8 +126,8 @@ def get_container_definitions():
Get container definitions from ECS service
"""
# Required parameters
cluster = os.environ.get('ECS_CLUSTER')
service = os.environ.get('ECS_SERVICE')
cluster = os.getenv('ECS_CLUSTER')
service = os.getenv('ECS_SERVICE')

# Validate required parameters
if not cluster:
Expand Down Expand Up @@ -166,10 +171,10 @@ def get_container_definitions():
output_content = yaml.dump(response, default_flow_style=False, sort_keys=False)

# Write to file if specified
if os.environ.get('OUTPUT_FILE'):
with open(os.environ.get('OUTPUT_FILE'), 'w') as f:
if os.getenv('OUTPUT_FILE'):
with open(os.getenv('OUTPUT_FILE'), 'w') as f:
f.write(output_content)
print(f"Output written to {os.environ.get('OUTPUT_FILE')}")
print(f"Output written to {os.getenv('OUTPUT_FILE')}")
else:
print(output_content)

Expand Down
6 changes: 3 additions & 3 deletions terragrunt-config-export/pipe.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ variables:
ECS_SERVICE:
description: Name of the ECS service
required: true
AWS_OIDC_ROLE_ARN:
description: ARN of IAM OIDC Role to assume
required: true
EXTRA_ENV:
type: Map
required: false
Expand All @@ -27,9 +30,6 @@ variables:
OUTPUT_FILE:
description: File to write the output to (if not specified, outputs to console)
required: false
AWS_ROLE_ARN:
description: ARN of IAM role to assume (optional)
required: false
AWS_PROFILE:
description: Profile to assume when running locally
required: false
Expand Down