Skip to content

Commit

Permalink
Upgrades of various sorts
Browse files Browse the repository at this point in the history
1. Added pre-commit gitleaks
2. Lock versions for testing
3. Added var.profile and var.region to allow greater control at runtime
4. Renamed script to aws_cli_runner.sh
5. Refactored variable processing and usage within output filename and
   passing to aws_cli_runner.sh
6. Updated all tests for latest version of Terraform (not idea I guess,
   but the main users are upgraded)
7. Replaced Travis CI with GitHub Actions
  • Loading branch information
rquadling committed Nov 24, 2023
1 parent 4c7e1b9 commit 812845f
Show file tree
Hide file tree
Showing 25 changed files with 278 additions and 87 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Build

on:
push:
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- run: jq --version; aws --version; terraform --version
- run: git clone https://github.com/tfutils/tfenv.git ~/.tfenv
- run: ~/.tfenv/bin/tfenv install
- uses: actions/checkout@v4
- run: tests/tests.sh
- uses: actions/upload-artifact@v2
if: always()
with:
name: logs
path: test-reports/**/*
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,8 @@ repos:
- --offset=2
- --sequence=4
- --width=300

- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.1
hooks:
- id: gitleaks
30 changes: 15 additions & 15 deletions .terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions .travis.yml

This file was deleted.

40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,40 @@ module "current_desired_capacity" {
}
```

## 3. Adding your own profile.

Extending the example above, you can supply your own profile by adding a `profile` to the module:

```hcl-terraform
module "current_desired_capacity" {
source = "digitickets/cli/aws"
assume_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/OrganizationAccountAccessRole"
role_session_name = "GettingDesiredCapacityFor${var.environment}"
aws_cli_commands = ["autoscaling", "describe-auto-scaling-groups"]
aws_cli_query = "AutoScalingGroups[?Tags[?Key==`Name`]|[?Value==`digitickets-${var.environment}-asg-app`]]|[0].DesiredCapacity"
profile = "your-own-profile"
}
```

## 4. Adding your external ID.

Extending the example above, you can supply your own external ID by adding an `external_id` to the module:

```hcl-terraform
module "current_desired_capacity" {
source = "digitickets/cli/aws"
assume_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/OrganizationAccountAccessRole"
role_session_name = "GettingDesiredCapacityFor${var.environment}"
aws_cli_commands = ["autoscaling", "describe-auto-scaling-groups"]
aws_cli_query = "AutoScalingGroups[?Tags[?Key==`Name`]|[?Value==`digitickets-${var.environment}-asg-app`]]|[0].DesiredCapacity"
profile = "your-own-profile"
external_id = "your-external-id"
}
```

Further information regarding the use of external IDs can be found [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html).


<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

Expand All @@ -65,7 +99,7 @@ module "current_desired_capacity" {

| Name | Version |
|------|---------|
| <a name="provider_external"></a> [external](#provider\_external) | 2.3.1 |
| <a name="provider_external"></a> [external](#provider\_external) | 2.3.2 |
| <a name="provider_local"></a> [local](#provider\_local) | 2.4.0 |

## Modules
Expand All @@ -84,10 +118,12 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_assume_role_arn"></a> [assume\_role\_arn](#input\_assume\_role\_arn) | The ARN of the role being assumed (optional) | `string` | `""` | no |
| <a name="input_external_id"></a> [external\_id](#input\_external\_id) | The external ID for assuming the role (optional) | `string` | `""` | no |
| <a name="input_aws_cli_commands"></a> [aws\_cli\_commands](#input\_aws\_cli\_commands) | The AWS CLI command and subcommands | `list(string)` | n/a | yes |
| <a name="input_aws_cli_query"></a> [aws\_cli\_query](#input\_aws\_cli\_query) | The --query value | `string` | `""` | no |
| <a name="input_debug_log_filename"></a> [debug\_log\_filename](#input\_debug\_log\_filename) | Generate a debug log if a `debug_log_filename` is supplied | `string` | `""` | no |
| <a name="input_external_id"></a> [external\_id](#input\_external\_id) | External id for assuming the role (optional) | `string` | `""` | no |
| <a name="input_profile"></a> [profile](#input\_profile) | The specific AWS profile to use (must be configured appropriately) | `string` | `""` | no |
| <a name="input_region"></a> [region](#input\_region) | The specific AWS region to use | `string` | `""` | no |
| <a name="input_role_session_name"></a> [role\_session\_name](#input\_role\_session\_name) | The role session name | `string` | `""` | no |

## Outputs
Expand Down
35 changes: 18 additions & 17 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
locals {
joined_aws_cli_command = join(" ", var.aws_cli_commands)
external_program_query = {
assume_role_arn = var.assume_role_arn
role_session_name = var.role_session_name
aws_cli_commands = local.joined_aws_cli_command
aws_cli_query = var.aws_cli_query
debug_log_filename = var.debug_log_filename
external_id = var.external_id
profile = var.profile
region = var.region
}
output_file = format(
"%s/temp/results-%s.json",
path.module,
md5(
join(
"-",
[
var.assume_role_arn,
var.role_session_name,
local.joined_aws_cli_command,
var.aws_cli_query,
var.debug_log_filename
]
values(local.external_program_query)
)
)
)
}

data "external" "awscli_program" {
program = [format("%s/scripts/awsWithAssumeRole.sh", path.module)]
query = {
assume_role_arn = var.assume_role_arn
role_session_name = var.role_session_name
aws_cli_commands = local.joined_aws_cli_command
aws_cli_query = var.aws_cli_query
output_file = local.output_file
debug_log_filename = var.debug_log_filename
external_id = var.external_id
}
program = [format("%s/scripts/aws_cli_runner.sh", path.module)]
query = merge(
local.external_program_query,
{
output_file = local.output_file
}
)
}

data "local_file" "awscli_results_file" {
Expand Down
25 changes: 19 additions & 6 deletions scripts/awsWithAssumeRole.sh → scripts/aws_cli_runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,28 @@ ASSUME_ROLE_ARN=$(echo "${TERRAFORM_QUERY}" | jq -r '.assume_role_arn')
ROLE_SESSION_NAME=$(echo "${TERRAFORM_QUERY}" | jq -r '.role_session_name')
DEBUG_LOG_FILENAME=$(echo "${TERRAFORM_QUERY}" | jq -r '.debug_log_filename')
EXTERNAL_ID=$(echo "${TERRAFORM_QUERY}" | jq -r '.external_id')
PROFILE_NAME=$(echo "${TERRAFORM_QUERY}" | jq -r '.profile')
REGION_NAME=$(echo "${TERRAFORM_QUERY}" | jq -r '.region')

# Do we have a profile?
if [ -n "${PROFILE_NAME}" ]; then
AWS_CLI_PROFILE_PARAM="--profile '${PROFILE_NAME}'"
fi

# Do we have a region?
if [ -n "${REGION_NAME}" ]; then
AWS_CLI_REGION_PARAM="--region '${REGION_NAME}'"
fi

# Do we need to assume a role?
if [ -n "${ASSUME_ROLE_ARN}" ]; then
if [-n "${EXTERNAL_ID}"]; then
TEMP_ROLE=$(aws sts assume-role --output json --role-arn "${ASSUME_ROLE_ARN}" --external-id "${EXTERNAL_ID}" --role-session-name "${ROLE_SESSION_NAME:-AssumingRole}")
else
TEMP_ROLE=$(aws sts assume-role --output json --role-arn "${ASSUME_ROLE_ARN}" --role-session-name "${ROLE_SESSION_NAME:-AssumingRole}")

# Do we have an external ID?
if [ -n "${EXTERNAL_ID}" ]; then
AWS_CLI_EXTERNAL_ID_PARAM="--external-id '${EXTERNAL_ID}'"
fi

TEMP_ROLE=$(aws sts assume-role ${AWS_CLI_PROFILE_PARAM:-} ${AWS_CLI_REGION_PARAM:-} --output json --role-arn "${ASSUME_ROLE_ARN}" ${AWS_CLI_EXTERNAL_ID_PARAM:-} --role-session-name "${ROLE_SESSION_NAME:-AssumingRole}")
export AWS_ACCESS_KEY_ID=$(echo "${TEMP_ROLE}" | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo "${TEMP_ROLE}" | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo "${TEMP_ROLE}" | jq -r '.Credentials.SessionToken')
Expand All @@ -40,7 +54,6 @@ if [ -n "${AWS_CLI_QUERY}" ]; then
fi

# Do we want to be debug?
export AWS_DEBUG_OPTION=""
if [ -n "${DEBUG_LOG_FILENAME}" ]; then
AWS_DEBUG_OPTION="--debug 2>${DEBUG_LOG_FILENAME}"
mkdir -p "$(dirname ${DEBUG_LOG_FILENAME})"
Expand All @@ -59,7 +72,7 @@ export AWS_PAGER=""
export AWS_RETRY_MODE=adaptive

# Run the AWS_CLI command, exiting with a non zero exit code if required.
if ! eval "aws ${AWS_CLI_COMMANDS} ${AWS_CLI_QUERY_PARAM:-} --output json ${AWS_DEBUG_OPTION}" >"${OUTPUT_FILE}" ; then
if ! eval "aws ${AWS_CLI_COMMANDS} ${AWS_CLI_PROFILE_PARAM:-} ${AWS_CLI_REGION_PARAM:-} ${AWS_CLI_QUERY_PARAM:-} --output json ${AWS_DEBUG_OPTION:-}" >"${OUTPUT_FILE}" ; then
echo "Error: aws failed."
exit 1
fi
Expand Down
12 changes: 1 addition & 11 deletions tests/bad_arn/test.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
#!/usr/bin/env bash

function run_test() {
if [[ -f $PLAN_FILE ]]; then
echo "Incorrectly generated a plan - $PLAN_FILE";
exit 1;
fi

if [[ ! -z "$(cat $PLAN_LOG_FILE)" ]]; then
echo "Incorrectly generated content in the plan log file - $PLAN_LOG_FILE";
exit 2;
fi

if [[ ! "$(cat $PLAN_ERROR_FILE)" == *'The optional ARN must match the format documented in'* ]]; then
echo 'Failed to detect invalid ARN.';
exit 3;
exit 1;
fi
}

Expand Down
32 changes: 32 additions & 0 deletions tests/invalid_profile_with_debug/expected_variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"assume_role_arn": {
"value": ""
},
"aws_cli_commands": {
"value": [
"s3api",
"list-objects",
"--bucket",
"ryft-public-sample-data",
"--no-sign-request"
]
},
"aws_cli_query": {
"value": "max_by(Contents, &Size)"
},
"debug_log_filename": {
"value": "test-reports/invalid_profile_with_debug/debug.log"
},
"external_id": {
"value": ""
},
"profile": {
"value": "this_profile_does_not_exist"
},
"region": {
"value": ""
},
"role_session_name": {
"value": "invalid_profile_with_debug"
}
}
6 changes: 6 additions & 0 deletions tests/invalid_profile_with_debug/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// ryft-public-sample-data is a publicly accessible S3 bucket.
aws_cli_commands = ["s3api", "list-objects", "--bucket", "ryft-public-sample-data", "--no-sign-request"]
aws_cli_query = "max_by(Contents, &Size)"
role_session_name = "invalid_profile_with_debug"
profile = "this_profile_does_not_exist"
debug_log_filename = "test-reports/invalid_profile_with_debug/debug.log"
20 changes: 20 additions & 0 deletions tests/invalid_profile_with_debug/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

function run_test() {
if [[ ! -f $PLAN_FILE ]]; then
echo "Failed to generate a plan - $PLAN_FILE";
exit 1;
fi

if [[ ! "$(terraform show -json $PLAN_FILE | jq -MSr .variables)" == "$(cat $EXPECTED_VARIABLES)" ]]; then
echo 'Failed to incorporate expected variable values into plan.';
exit 2;
fi

if [[ ! "$(cat $DEBUG_LOG_FILE)" == *'The config profile (this_profile_does_not_exist) could not be found'* ]]; then
echo 'Failed to generate error from bad profile name.';
exit 3;
fi
}

. tests/common.sh $0
32 changes: 32 additions & 0 deletions tests/invalid_profile_without_debug/expected_variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"assume_role_arn": {
"value": ""
},
"aws_cli_commands": {
"value": [
"s3api",
"list-objects",
"--bucket",
"ryft-public-sample-data",
"--no-sign-request"
]
},
"aws_cli_query": {
"value": "max_by(Contents, &Size)"
},
"debug_log_filename": {
"value": ""
},
"external_id": {
"value": ""
},
"profile": {
"value": "this_profile_does_not_exist"
},
"region": {
"value": ""
},
"role_session_name": {
"value": "invalid_profile_without_debug"
}
}
5 changes: 5 additions & 0 deletions tests/invalid_profile_without_debug/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// ryft-public-sample-data is a publicly accessible S3 bucket.
aws_cli_commands = ["s3api", "list-objects", "--bucket", "ryft-public-sample-data", "--no-sign-request"]
aws_cli_query = "max_by(Contents, &Size)"
role_session_name = "invalid_profile_without_debug"
profile = "this_profile_does_not_exist"
20 changes: 20 additions & 0 deletions tests/invalid_profile_without_debug/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

function run_test() {
if [[ ! -f $PLAN_FILE ]]; then
echo "Failed to generate a plan - $PLAN_FILE";
exit 1;
fi

if [[ ! "$(terraform show -json $PLAN_FILE | jq -MSr .variables)" == "$(cat $EXPECTED_VARIABLES)" ]]; then
echo 'Failed to incorporate expected variable values into plan.';
exit 2;
fi

if [[ ! "$(cat $PLAN_ERROR_FILE)" == *'The config profile (this_profile_does_not_exist) could not be found'* ]]; then
echo 'Failed to generate error from bad profile name during planning.';
exit 3;
fi
}

. tests/common.sh $0
Loading

0 comments on commit 812845f

Please sign in to comment.