Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
c377973
first draft policy
dshack1 Oct 25, 2025
950238b
update folder name for correct naming
dshack1 Oct 25, 2025
aaaceed
Create user-activity.yml
dshack1 Oct 25, 2025
3ee508c
Update user-activity.yml
dshack1 Oct 25, 2025
5c0889c
Create user-activity-org.yml
dshack1 Oct 25, 2025
e1bb5db
Update user-activity.yml
dshack1 Oct 25, 2025
42c990f
Update user-activity.yml
dshack1 Oct 25, 2025
090ea34
Update user-activity.yml
dshack1 Oct 25, 2025
88d6cd2
Update user-activity.yml
dshack1 Oct 26, 2025
e2a8af0
Update user-activity.yml
dshack1 Oct 26, 2025
2ee3bf0
Update user-activity.yml
dshack1 Oct 26, 2025
bc5bb36
Update user-activity.yml
dshack1 Oct 26, 2025
baa3f1b
Create team-membership-audit.yml
dshack1 Oct 26, 2025
12a245a
Update team-membership-audit.yml
dshack1 Oct 26, 2025
b9ae3fd
Update team-membership-audit.yml
dshack1 Oct 26, 2025
7cb0fa6
Update team-membership-audit.yml
dshack1 Oct 26, 2025
36610f5
Update team-membership-audit.yml
dshack1 Oct 26, 2025
6a2083c
Update team-membership-audit.yml
dshack1 Oct 26, 2025
3374418
Update team-membership-audit.yml
dshack1 Oct 26, 2025
da57d6e
Update team-membership-audit.yml
dshack1 Oct 26, 2025
b938c3b
Update team-membership-audit.yml
dshack1 Oct 26, 2025
eebffb0
Update team-membership-audit.yml
dshack1 Oct 26, 2025
679aeba
Update team-membership-audit.yml
dshack1 Oct 26, 2025
47ea765
Update team-membership-audit.yml
dshack1 Oct 26, 2025
1f02aa5
Update team-membership-audit.yml
dshack1 Oct 26, 2025
3efc8ab
Update team-membership-audit.yml
dshack1 Oct 26, 2025
2ef2322
Create iam-users-master.yml
dshack1 Nov 29, 2025
5ec7983
Update iam-users-master.yml
dshack1 Nov 29, 2025
07def8d
testing
dshack1 Nov 29, 2025
28afe5d
Update iam-users-master.yml
dshack1 Nov 29, 2025
9110ef4
Create iam-users-terraform.yml
dshack1 Nov 30, 2025
ed149b3
adding terraform
Nov 30, 2025
01e6bc1
Update iam-users-terraform.yml
dshack1 Nov 30, 2025
a99c1f6
change file location
Nov 30, 2025
2dd3d94
saving files
Nov 30, 2025
e35bf25
adding readme
Nov 30, 2025
efcbfe6
updating workflow
Nov 30, 2025
8a3972c
updating workflow for PR plans
Nov 30, 2025
a615171
adding user test pr
Nov 30, 2025
c0ce817
removing users
dshack1 Dec 1, 2025
bd60236
Merge pull request #3 from Cloudnest-Advisory/test-pr-tf
dshack1 Dec 1, 2025
0abdb4e
updating workflow
dshack1 Dec 14, 2025
f1dc5f1
Merge branch 'main' of https://github.com/Cloudnest-Advisory/greensta…
dshack1 Dec 14, 2025
fbc2e55
adding user
dshack1 Dec 14, 2025
980cf71
updating workflow and remove user
dshack1 Dec 14, 2025
841f59a
updating workflow and remove user
dshack1 Dec 14, 2025
6837e6a
adding outputs
dshack1 Dec 14, 2025
ce6f735
update terraform
dshack1 Dec 14, 2025
fc26071
update terraform
dshack1 Dec 14, 2025
466640d
update workflow
dshack1 Dec 14, 2025
6878449
update workflow
dshack1 Dec 14, 2025
0aad44a
update workflow
dshack1 Dec 14, 2025
96fbb26
update workflow with email validation send
dshack1 Dec 14, 2025
e2f26d7
adding sent_emails json
dshack1 Dec 14, 2025
9ef7783
adding write and commit
dshack1 Dec 14, 2025
98d6229
adding write and commit
dshack1 Dec 14, 2025
f0444fc
updating workflow
dshack1 Dec 14, 2025
8a9eca4
updating workflow
dshack1 Dec 14, 2025
f0f2c61
updating workflow
dshack1 Dec 14, 2025
e75e56f
chore: record sent SES emails
github-actions[bot] Dec 14, 2025
c799e2d
updating workflow to remove ses block
dshack1 Dec 14, 2025
c346a7d
Merge branch 'main' of https://github.com/Cloudnest-Advisory/greensta…
dshack1 Dec 14, 2025
0c9c7a3
updating workflow to remove ses block
dshack1 Dec 14, 2025
70adb24
deleting user
dshack1 Dec 14, 2025
7031c58
update workflow
dshack1 Dec 14, 2025
fb03973
add user
dshack1 Dec 14, 2025
181a933
add user
dshack1 Dec 14, 2025
e5aa5c0
adding new user
dshack1 Dec 14, 2025
f51e9da
update workflow plan_guard variable
dshack1 Dec 14, 2025
c65b1ee
update workflow
dshack1 Dec 14, 2025
d5e369b
update
dshack1 Dec 14, 2025
46a2ed8
update
dshack1 Dec 14, 2025
e3d986c
update
dshack1 Dec 14, 2025
fd6a301
update
dshack1 Dec 14, 2025
fc23751
update
dshack1 Dec 14, 2025
e0a5417
update
dshack1 Dec 14, 2025
5f9786f
update fixed
dshack1 Dec 14, 2025
8a66471
update fixed
dshack1 Dec 14, 2025
3d80495
update fixed
dshack1 Dec 14, 2025
0e45141
update fixed
dshack1 Dec 14, 2025
a70e2d9
update fixed
dshack1 Dec 14, 2025
dd1f8a4
chore: record sent SES emails
github-actions[bot] Dec 14, 2025
8fb0939
update fixed
dshack1 Dec 14, 2025
4c1a20f
update fixed
dshack1 Dec 14, 2025
2a05cbb
adding new updates
dshack1 Dec 17, 2025
6b6430d
testing delete
dshack1 Dec 17, 2025
a2af092
chore: record sent SES emails
github-actions[bot] Dec 17, 2025
42b136d
testing create
dshack1 Dec 17, 2025
5e5b92f
chore: record sent SES emails
github-actions[bot] Dec 17, 2025
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
284 changes: 284 additions & 0 deletions .github/workflows/iam-users-terraform.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
name: IAM Users – Terraform

on:
workflow_dispatch: {}
# inputs:
# send_emails:
# description: "Send SES emails after apply?"
# required: true
# type: choice
# options:
# - no
# - yes

pull_request:
paths:
- 'terraform/iam-users/**'


jobs:
terraform:
runs-on: ubuntu-latest
permissions:
id-token: write # needed for OIDC
contents: write

env:
AWS_REGION: us-east-1

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::155729781479:role/github-user # or a GitHubTerraformRole if you create one
aws-region: ${{ env.AWS_REGION }}

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.8.0

- name: Terraform Init
working-directory: terraform/iam-users
run: terraform init

- name: Terraform Plan
working-directory: terraform/iam-users
run: terraform plan -out=tfplan

# Only apply on manual run or non-PR events (for example push to main or workflow_dispatch)
- name: Terraform Apply
if: github.event_name != 'pull_request'
working-directory: terraform/iam-users
run: terraform apply -auto-approve tfplan

- name: Detect Terraform creates/deletes
id: plan_guard
working-directory: terraform/iam-users
shell: bash
run: |
set -euo pipefail

# Assumes you already ran: terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json

# Look for resource change actions
has_creates=$(jq -r '
any(.resource_changes[]?; (.change.actions | index("create")) != null)
' tfplan.json)

has_deletes=$(jq -r '
any(.resource_changes[]?; (.change.actions | index("delete")) != null)
' tfplan.json)

echo "has_creates=$has_creates"
echo "has_deletes=$has_deletes"

# Expose as GitHub Actions step outputs
echo "has_creates=$has_creates" >> "$GITHUB_OUTPUT"
echo "has_deletes=$has_deletes" >> "$GITHUB_OUTPUT"

- name: Get user emails from Terraform outputs
if: github.event_name != 'pull_request'
id: tf_outputs
working-directory: terraform/iam-users
run: |
set -euo pipefail
emails_json=$(terraform output -json user_emails)
echo "emails_json=$emails_json" >> "$GITHUB_OUTPUT"

# Send an email via SES to each user
- name: Send SES emails to users
if: github.event_name != 'pull_request' && steps.plan_guard.outputs.has_creates == 'true'
id: email_sent_id
working-directory: terraform/iam-users
env:
SES_FROM_ADDRESS: "info@cloudnestadvisory.com"
EMAILS_JSON: ${{ steps.tf_outputs.outputs.emails_json }}
email_sent: false
run: |
set -euo pipefail

# ------------------------------------------------------------
# 1) Sent-email log file: tracks which usernames we've already emailed
# so we do not send duplicates on future runs.
# ------------------------------------------------------------
SENT_FILE="sent_emails.json"

# Ensure sent log exists
if [ ! -f "$SENT_FILE" ]; then
echo "{}" > "$SENT_FILE"
fi

# Load current sent state into a variable

sent=$(cat "$SENT_FILE")

echo "Current sent email log:"
echo "$sent" | jq .

# ------------------------------------------------------------
# 2) Confirm we received the emails map from Terraform outputs
# EMAILS_JSON should look like: {"vol-a":"a@x.com","vol-b":"b@x.com"}
# ------------------------------------------------------------

echo "EMAILS_JSON received:"
echo "$EMAILS_JSON" | jq .

#Old Above Below ------
# echo "$EMAILS_JSON" | jq -r 'to_entries[] | "\(.key) \(.value)"' | while read username email; do
# echo "Sending email to $email for user $username"
# Old Code Above -------

# ------------------------------------------------------------
# 3) Loop through each (username, email) pair and only send for NEW users
# Use process substitution to avoid subshell issues from pipes.
# ------------------------------------------------------------
echo "$EMAILS_JSON" | jq -r 'to_entries[] | "\(.key) \(.value)"' | while read -r username email; do
already_sent=$(echo "$sent" | jq -r --arg u "$username" 'has($u)')

if [ "$already_sent" = "true" ]; then
echo "Skipping $username ($email) — already emailed"
continue
fi

echo "Sending email to $email for user $username"

# ------------------------------------------------------------
# 4) Build SES message payload as JSON file to avoid CLI quoting issues
# ------------------------------------------------------------
cat > ses-message.json <<EOF
{
"Subject": { "Data": "Your IAM access has been configured" },
"Body": {
"Text": {
"Data": "Hello,\n\nYour IAM user \"${username}\" has been created or updated in AWS.\n\nIf you were expecting new access, you should now be able to sign in or use your credentials (delivered to you through our normal secure channel).\n\nIf you did not expect this change, please contact the admin team immediately."
}
}
}
EOF

# ------------------------------------------------------------
# 5) Send email via SES
# ------------------------------------------------------------
aws ses send-email \
--region "$AWS_REGION" \
--from "$SES_FROM_ADDRESS" \
--destination "ToAddresses=$email" \
--message file://ses-message.json

# ------------------------------------------------------------
# 6) Record successful send in sent_emails.json (in-memory + on-disk)
# ------------------------------------------------------------

now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
sent=$(echo "$sent" | jq --arg u "$username" --arg t "$now" '. + {($u): $t}')
echo "$sent" > "$SENT_FILE"

# ------------------------------------------------------------
# 7) Final debug: show updated sent log so you can confirm it changed
# ------------------------------------------------------------
echo "Updated sent email log (file):"
cat "$SENT_FILE" | jq .

done

email_sent=true
echo "email_sent=true" >> "$GITHUB_OUTPUT"

- name: Cleanup sent email log for deleted users
if: github.event_name != 'pull_request' && steps.plan_guard.outputs.has_deletes == 'true'
id: cleanup_sent_log
working-directory: terraform/iam-users
env:
SES_FROM_ADDRESS: "info@cloudnestadvisory.com"
EMAILS_JSON: ${{ steps.tf_outputs.outputs.emails_json }}
email_sent: false
shell: bash
run: |
set -euo pipefail

SENT_FILE="sent_emails.json"

# Ensure log exists
if [ ! -f "$SENT_FILE" ]; then
echo "{}" > "$SENT_FILE"
fi

# Ensure we have plan JSON available
terraform show -json tfplan > tfplan.json

echo "Current sent email log:"
cat "$SENT_FILE" | jq .

# Pull usernames being deleted from the plan (IAM users)
deleted_users=$(jq -r '
[.resource_changes[]?
| select(.type=="aws_iam_user")
| select(.change.actions | index("delete"))
| .change.before.name
] | unique | .[]
' tfplan.json || true)

if [ -z "${deleted_users:-}" ]; then
echo "No deleted IAM users found in plan. Nothing to clean."
exit 0
fi

echo "Usernames to remove from sent log:"
echo "$deleted_users"

# Load current sent log into memory once, delete keys, write once
sent=$(cat "$SENT_FILE")

while IFS= read -r username; do
[ -z "$username" ] && continue
echo "Removing $username from $SENT_FILE (if present)..."
sent=$(echo "$sent" | jq --arg u "$username" 'del(.[$u])')
done <<< "$deleted_users"

echo "$sent" > "$SENT_FILE"

echo "Updated sent email log (file):"
cat "$SENT_FILE" | jq .

- name: Commit sent email log
#if: steps.email_sent_id.outputs.email_sent == 'true'
working-directory: terraform/iam-users
env:
email_sent_ses: ${{ steps.email_sent_id.outputs.email_sent }}
run: |
set -euo pipefail
echo "Emailis true or flase:$email_sent_ses"

# ------------------------------------------------------------
# 1) Identify this commit as coming from GitHub Actions
# ------------------------------------------------------------
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# ------------------------------------------------------------
# 2) Stage the sent email log (this is the only file we care about)
# ------------------------------------------------------------
git add sent_emails.json

# ------------------------------------------------------------
# 3) If the staged file has NOT changed, exit cleanly
# This prevents empty commits when:
# - no emails were sent
# - users were removed
# - apply was a no-op
# ------------------------------------------------------------
if git diff --cached --quiet; then
echo "sent_emails.json unchanged. Nothing to commit."
exit 0
fi

# ------------------------------------------------------------
# 4) Commit and push the updated sent email log
# ------------------------------------------------------------
git commit -m "chore: record sent SES emails"
git push
Loading