diff --git a/.gitignore b/.gitignore
index a79d9a9..9fda474 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,26 +1,5 @@
-*.log
-*.pem
-aws-eump-logs/
-dynamodb-tutorial-logs/
-Dockerfile
-document.png
-dashboard-body-*.json
-comprehend-policy.json
-hello-world.json
-input.json
-query-results.csv
-sentiment-*.json
-step-functions-trust-policy.json
-stepfunctions-policy.json
-textract-*.json
-updated-hello-world.json
-webserver-template-*.yaml
-qbusiness-*.json
-datazone_script_v3_fixed.log
-idc_setup_*.log
workspaces_creation.log
-logs/
-*.csv
-*.png
-Dockerfile
-cfn/
+datazone_script_v3_fixed.log
+idc_setup_20260429_064540.log
+qbusiness-permissions-policy.json
+qbusiness-trust-policy.json
diff --git a/tuts/001-lightsail-gs/lightsail-gs.sh b/tuts/001-lightsail-gs/lightsail-gs.sh
index 740adde..f00e010 100644
--- a/tuts/001-lightsail-gs/lightsail-gs.sh
+++ b/tuts/001-lightsail-gs/lightsail-gs.sh
@@ -122,7 +122,8 @@ aws lightsail create-instances \
--availability-zone "$AVAILABILITY_ZONE" \
--blueprint-id amazon_linux_2023 \
--bundle-id nano_3_0 \
- --region "$AWS_REGION"
+ --region "$AWS_REGION" \
+ --tags key=project,value=doc-smith key=tutorial,value=lightsail-gs
check_status "Failed to create Lightsail instance"
track_resource "instance" "$INSTANCE_NAME"
@@ -180,7 +181,8 @@ aws lightsail create-disk \
--disk-name "$DISK_NAME" \
--availability-zone "$AVAILABILITY_ZONE" \
--size-in-gb 8 \
- --region "$AWS_REGION"
+ --region "$AWS_REGION" \
+ --tags key=project,value=doc-smith key=tutorial,value=lightsail-gs
check_status "Failed to create disk"
track_resource "disk" "$DISK_NAME"
@@ -223,7 +225,8 @@ echo "Step 6: Creating snapshot of the instance: $SNAPSHOT_NAME"
aws lightsail create-instance-snapshot \
--instance-name "$INSTANCE_NAME" \
--instance-snapshot-name "$SNAPSHOT_NAME" \
- --region "$AWS_REGION"
+ --region "$AWS_REGION" \
+ --tags key=project,value=doc-smith key=tutorial,value=lightsail-gs
check_status "Failed to create instance snapshot"
track_resource "instance_snapshot" "$SNAPSHOT_NAME"
diff --git a/tuts/002-vpc-gs/vpc-gs.sh b/tuts/002-vpc-gs/vpc-gs.sh
index a563a54..fa97dee 100644
--- a/tuts/002-vpc-gs/vpc-gs.sh
+++ b/tuts/002-vpc-gs/vpc-gs.sh
@@ -115,7 +115,7 @@ fi
# Create VPC
echo "Creating VPC with CIDR block 10.0.0.0/16..."
-VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=MyVPC}]' --query 'Vpc.VpcId' --output text)
+VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=MyVPC},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' --query 'Vpc.VpcId' --output text)
if [ -z "$VPC_ID" ]; then
handle_error "Failed to create VPC"
@@ -146,7 +146,7 @@ PUBLIC_SUBNET_AZ1=$(aws ec2 create-subnet \
--vpc-id "$VPC_ID" \
--cidr-block 10.0.0.0/24 \
--availability-zone "$AZ1" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Public-Subnet-AZ1}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Public-Subnet-AZ1},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'Subnet.SubnetId' \
--output text)
@@ -162,7 +162,7 @@ PUBLIC_SUBNET_AZ2=$(aws ec2 create-subnet \
--vpc-id "$VPC_ID" \
--cidr-block 10.0.1.0/24 \
--availability-zone "$AZ2" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Public-Subnet-AZ2}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Public-Subnet-AZ2},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'Subnet.SubnetId' \
--output text)
@@ -179,7 +179,7 @@ PRIVATE_SUBNET_AZ1=$(aws ec2 create-subnet \
--vpc-id "$VPC_ID" \
--cidr-block 10.0.2.0/24 \
--availability-zone "$AZ1" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Private-Subnet-AZ1}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Private-Subnet-AZ1},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'Subnet.SubnetId' \
--output text)
@@ -195,7 +195,7 @@ PRIVATE_SUBNET_AZ2=$(aws ec2 create-subnet \
--vpc-id "$VPC_ID" \
--cidr-block 10.0.3.0/24 \
--availability-zone "$AZ2" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Private-Subnet-AZ2}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Private-Subnet-AZ2},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'Subnet.SubnetId' \
--output text)
@@ -209,7 +209,7 @@ echo "Private subnet created in $AZ2 with ID: $PRIVATE_SUBNET_AZ2"
# Create Internet Gateway
echo "Creating Internet Gateway..."
IGW_ID=$(aws ec2 create-internet-gateway \
- --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=MyIGW}]' \
+ --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=MyIGW},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'InternetGateway.InternetGatewayId' \
--output text)
@@ -228,7 +228,7 @@ aws ec2 attach-internet-gateway --internet-gateway-id "$IGW_ID" --vpc-id "$VPC_I
echo "Creating public route table..."
PUBLIC_RT=$(aws ec2 create-route-table \
--vpc-id "$VPC_ID" \
- --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=Public-RT}]' \
+ --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=Public-RT},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'RouteTable.RouteTableId' \
--output text)
@@ -266,7 +266,7 @@ CREATED_RESOURCES+=("ROUTE_TABLE_ASSOCIATION:$PUBLIC_RT_ASSOC_2")
echo "Creating private route table..."
PRIVATE_RT=$(aws ec2 create-route-table \
--vpc-id "$VPC_ID" \
- --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=Private-RT}]' \
+ --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=Private-RT},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'RouteTable.RouteTableId' \
--output text)
@@ -298,7 +298,7 @@ CREATED_RESOURCES+=("ROUTE_TABLE_ASSOCIATION:$PRIVATE_RT_ASSOC_2")
# Allocate Elastic IP for NAT Gateway
echo "Allocating Elastic IP for NAT Gateway..."
-EIP_ALLOC=$(aws ec2 allocate-address --domain vpc --query 'AllocationId' --output text)
+EIP_ALLOC=$(aws ec2 allocate-address --domain vpc --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' --query 'AllocationId' --output text)
if [ -z "$EIP_ALLOC" ]; then
handle_error "Failed to allocate Elastic IP"
@@ -312,7 +312,7 @@ echo "Creating NAT Gateway in public subnet in $AZ1..."
NAT_GW=$(aws ec2 create-nat-gateway \
--subnet-id "$PUBLIC_SUBNET_AZ1" \
--allocation-id "$EIP_ALLOC" \
- --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=MyNATGateway}]' \
+ --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=MyNATGateway},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'NatGateway.NatGatewayId' \
--output text)
@@ -344,6 +344,7 @@ WEB_SG=$(aws ec2 create-security-group \
--group-name "WebServerSG-$(date +%s)" \
--description "Security group for web servers" \
--vpc-id "$VPC_ID" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'GroupId' \
--output text)
@@ -370,6 +371,7 @@ DB_SG=$(aws ec2 create-security-group \
--group-name "DBServerSG-$(date +%s)" \
--description "Security group for database servers" \
--vpc-id "$VPC_ID" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'GroupId' \
--output text)
@@ -428,7 +430,7 @@ echo "Deploying EC2 instances..."
# Create key pair for SSH access
KEY_NAME="vpc-tutorial-key-$(date +%s)"
echo "Creating key pair $KEY_NAME..."
-aws ec2 create-key-pair --key-name "$KEY_NAME" --query 'KeyMaterial' --output text > "${KEY_NAME}.pem" || handle_error "Failed to create key pair"
+aws ec2 create-key-pair --key-name "$KEY_NAME" --tag-specifications 'ResourceType=key-pair,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' --query 'KeyMaterial' --output text > "${KEY_NAME}.pem" || handle_error "Failed to create key pair"
chmod 400 "${KEY_NAME}.pem"
echo "Key pair saved to ${KEY_NAME}.pem"
CREATED_RESOURCES+=("KEY_PAIR:$KEY_NAME")
@@ -456,7 +458,7 @@ WEB_INSTANCE=$(aws ec2 run-instances \
systemctl start httpd
systemctl enable httpd
echo "
Hello from $(hostname -f) in the public subnet
" > /var/www/html/index.html' \
- --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=WebServer}]' \
+ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=WebServer},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'Instances[0].InstanceId' \
--output text) || handle_error "Failed to launch web server"
echo "Web server instance created with ID: $WEB_INSTANCE"
@@ -486,7 +488,7 @@ DB_INSTANCE=$(aws ec2 run-instances \
yum install -y mariadb-server
systemctl start mariadb
systemctl enable mariadb' \
- --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=DBServer}]' \
+ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=DBServer},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-gs}]' \
--query 'Instances[0].InstanceId' \
--output text) || handle_error "Failed to launch database server"
echo "Database server instance created with ID: $DB_INSTANCE"
diff --git a/tuts/003-s3-gettingstarted/s3-gettingstarted.sh b/tuts/003-s3-gettingstarted/s3-gettingstarted.sh
index a835eb7..f345979 100644
--- a/tuts/003-s3-gettingstarted/s3-gettingstarted.sh
+++ b/tuts/003-s3-gettingstarted/s3-gettingstarted.sh
@@ -169,6 +169,23 @@ if [ "$BUCKET_IS_SHARED" = "false" ]; then
fi
CREATED_RESOURCES+=("s3:bucket:${BUCKET_NAME}")
echo "Bucket created."
+
+ if ! aws s3api put-bucket-tagging \
+ --bucket "$BUCKET_NAME" \
+ --tagging '{
+ "TagSet": [
+ {
+ "Key": "project",
+ "Value": "doc-smith"
+ },
+ {
+ "Key": "tutorial",
+ "Value": "s3-gettingstarted"
+ }
+ ]
+ }' >/dev/null 2>&1; then
+ echo "WARNING: Failed to tag bucket"
+ fi
fi
echo ""
@@ -317,12 +334,29 @@ LOG_TARGET_BUCKET="${BUCKET_NAME}-logs"
if [ "$BUCKET_IS_SHARED" = "false" ]; then
REGION=$(get_region)
if [ "$REGION" = "us-east-1" ]; then
- aws s3api create-bucket --bucket "$LOG_TARGET_BUCKET" 2>/dev/null || true
+ aws s3api create-bucket --bucket "$LOG_TARGET_BUCKET" >/dev/null 2>&1 || true
else
aws s3api create-bucket \
--bucket "$LOG_TARGET_BUCKET" \
--region "$REGION" \
- --create-bucket-configuration LocationConstraint="$REGION" 2>/dev/null || true
+ --create-bucket-configuration LocationConstraint="$REGION" >/dev/null 2>&1 || true
+ fi
+
+ if ! aws s3api put-bucket-tagging \
+ --bucket "$LOG_TARGET_BUCKET" \
+ --tagging '{
+ "TagSet": [
+ {
+ "Key": "project",
+ "Value": "doc-smith"
+ },
+ {
+ "Key": "tutorial",
+ "Value": "s3-gettingstarted"
+ }
+ ]
+ }' >/dev/null 2>&1; then
+ echo "WARNING: Failed to tag log bucket"
fi
aws s3api put-bucket-acl --bucket "$LOG_TARGET_BUCKET" --acl log-delivery-write 2>/dev/null || true
@@ -354,6 +388,14 @@ if ! aws s3api put-bucket-tagging \
--bucket "$BUCKET_NAME" \
--tagging '{
"TagSet": [
+ {
+ "Key": "project",
+ "Value": "doc-smith"
+ },
+ {
+ "Key": "tutorial",
+ "Value": "s3-gettingstarted"
+ },
{
"Key": "Environment",
"Value": "Tutorial"
diff --git a/tuts/004-cloudmap-custom-attributes/cloudmap-custom-attributes.sh b/tuts/004-cloudmap-custom-attributes/cloudmap-custom-attributes.sh
index 8b641ec..9d218fe 100644
--- a/tuts/004-cloudmap-custom-attributes/cloudmap-custom-attributes.sh
+++ b/tuts/004-cloudmap-custom-attributes/cloudmap-custom-attributes.sh
@@ -180,7 +180,7 @@ NAMESPACE_ID=$(aws servicediscovery list-namespaces --query "Namespaces[?Name=='
if [[ -z "$NAMESPACE_ID" || "$NAMESPACE_ID" == "None" ]]; then
log_cmd "aws servicediscovery create-http-namespace --name cloudmap-tutorial --creator-request-id namespace-request-\$(date +%s)"
- OPERATION_ID=$(aws servicediscovery create-http-namespace --name cloudmap-tutorial --creator-request-id "namespace-request-$(date +%s)" --query 'OperationId' --output text)
+ OPERATION_ID=$(aws servicediscovery create-http-namespace --name cloudmap-tutorial --creator-request-id "namespace-request-$(date +%s)" --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-custom-attributes --query 'OperationId' --output text)
# Wait for namespace creation to complete
echo "Waiting for namespace creation to complete..." | tee -a "$LOG_FILE"
@@ -202,7 +202,7 @@ echo "Step 2: Creating DynamoDB table..." | tee -a "$LOG_FILE"
TABLE_EXISTS=$(aws dynamodb describe-table --table-name cloudmap 2>&1 || echo "NOT_EXISTS")
if [[ $TABLE_EXISTS == *"ResourceNotFoundException"* || $TABLE_EXISTS == "NOT_EXISTS" ]]; then
- log_cmd "aws dynamodb create-table --table-name cloudmap --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST"
+ log_cmd "aws dynamodb create-table --table-name cloudmap --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-custom-attributes"
# Wait for DynamoDB table to become active
echo "Waiting for DynamoDB table to become active..." | tee -a "$LOG_FILE"
@@ -235,7 +235,7 @@ if [[ -z "$DATA_SERVICE_ID" ]]; then
echo "Data service does not exist, creating it..." | tee -a "$LOG_FILE"
# Create the service and capture the ID directly
echo "$ aws servicediscovery create-service --name data-service --namespace-id $NAMESPACE_ID --creator-request-id data-service-request-\$(date +%s)" | tee -a "$LOG_FILE"
- CREATE_OUTPUT=$(aws servicediscovery create-service --name data-service --namespace-id "$NAMESPACE_ID" --creator-request-id "data-service-request-$(date +%s)")
+ CREATE_OUTPUT=$(aws servicediscovery create-service --name data-service --namespace-id "$NAMESPACE_ID" --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-custom-attributes --creator-request-id "data-service-request-$(date +%s)")
echo "$CREATE_OUTPUT" | tee -a "$LOG_FILE"
# Extract the service ID using AWS CLI query
@@ -292,6 +292,7 @@ ROLE_EXISTS=$(aws iam get-role --role-name cloudmap-tutorial-role 2>&1 || echo "
if [[ $ROLE_EXISTS == *"NoSuchEntity"* || $ROLE_EXISTS == "NOT_EXISTS" ]]; then
log_cmd "aws iam create-role --role-name cloudmap-tutorial-role --assume-role-policy-document file://lambda-trust-policy.json"
+ aws iam tag-role --role-name cloudmap-tutorial-role --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-custom-attributes
else
echo "Role cloudmap-tutorial-role already exists, using existing role" | tee -a "$LOG_FILE"
fi
@@ -375,7 +376,7 @@ if [[ -z "$APP_SERVICE_ID" ]]; then
echo "App service does not exist, creating it..." | tee -a "$LOG_FILE"
# Create the service and capture the ID directly
echo "$ aws servicediscovery create-service --name app-service --namespace-id $NAMESPACE_ID --creator-request-id app-service-request-\$(date +%s)" | tee -a "$LOG_FILE"
- CREATE_OUTPUT=$(aws servicediscovery create-service --name app-service --namespace-id "$NAMESPACE_ID" --creator-request-id "app-service-request-$(date +%s)")
+ CREATE_OUTPUT=$(aws servicediscovery create-service --name app-service --namespace-id "$NAMESPACE_ID" --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-custom-attributes --creator-request-id "app-service-request-$(date +%s)")
echo "$CREATE_OUTPUT" | tee -a "$LOG_FILE"
# Extract the service ID using AWS CLI query
@@ -448,7 +449,7 @@ log_cmd "zip writefunction.zip writefunction.py"
# Create the Lambda function
FUNCTION_EXISTS=$(aws lambda list-functions --query "Functions[?FunctionName=='writefunction'].FunctionName" --output text 2>/dev/null || echo "")
if [[ -z "$FUNCTION_EXISTS" ]]; then
- log_cmd "aws lambda create-function --function-name writefunction --runtime python3.12 --role $ROLE_ARN --handler writefunction.lambda_handler --zip-file fileb://writefunction.zip --architectures x86_64 --timeout 10"
+ log_cmd "aws lambda create-function --function-name writefunction --runtime python3.12 --role $ROLE_ARN --handler writefunction.lambda_handler --zip-file fileb://writefunction.zip --architectures x86_64 --timeout 10 --tags project=doc-smith,tutorial=cloudmap-custom-attributes"
# Wait for the Lambda function to be active before updating
echo "Waiting for Lambda function to become active..." | tee -a "$LOG_FILE"
@@ -537,7 +538,7 @@ log_cmd "zip readfunction.zip readfunction.py"
# Create the Lambda function
FUNCTION_EXISTS=$(aws lambda list-functions --query "Functions[?FunctionName=='readfunction'].FunctionName" --output text 2>/dev/null || echo "")
if [[ -z "$FUNCTION_EXISTS" ]]; then
- log_cmd "aws lambda create-function --function-name readfunction --runtime python3.12 --role $ROLE_ARN --handler readfunction.lambda_handler --zip-file fileb://readfunction.zip --architectures x86_64 --timeout 10"
+ log_cmd "aws lambda create-function --function-name readfunction --runtime python3.12 --role $ROLE_ARN --handler readfunction.lambda_handler --zip-file fileb://readfunction.zip --architectures x86_64 --timeout 10 --tags project=doc-smith,tutorial=cloudmap-custom-attributes"
# Wait for the Lambda function to be active before updating
echo "Waiting for Lambda function to become active..." | tee -a "$LOG_FILE"
diff --git a/tuts/005-cloudfront-gettingstarted/cloudfront-gettingstarted.sh b/tuts/005-cloudfront-gettingstarted/cloudfront-gettingstarted.sh
index 4c8f1af..c3e9af7 100644
--- a/tuts/005-cloudfront-gettingstarted/cloudfront-gettingstarted.sh
+++ b/tuts/005-cloudfront-gettingstarted/cloudfront-gettingstarted.sh
@@ -179,6 +179,8 @@ if [ "$BUCKET_IS_SHARED" != "true" ]; then
handle_error "Failed to create S3 bucket"
fi
+ aws s3api put-bucket-tagging --bucket "$BUCKET_NAME" --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=cloudfront-gettingstarted}]'
+
# Batch bucket configuration calls for efficiency
aws s3api put-bucket-versioning --bucket "$BUCKET_NAME" --versioning-configuration Status=Enabled &
aws s3api put-public-access-block \
@@ -335,6 +337,9 @@ fi
echo "Created CloudFront distribution with ID: $DISTRIBUTION_ID"
echo "CloudFront domain name: $DOMAIN_NAME"
+# Tag the CloudFront distribution
+aws cloudfront tag-resource --resource "arn:aws:cloudfront::$ACCOUNT_ID:distribution/$DISTRIBUTION_ID" --tags 'Items=[{Key=project,Value=doc-smith},{Key=tutorial,Value=cloudfront-gettingstarted}]'
+
# Step 6: Update S3 bucket policy
echo "Updating S3 bucket policy..."
diff --git a/tuts/008-vpc-private-servers-gs/vpc-private-servers-gs.sh b/tuts/008-vpc-private-servers-gs/vpc-private-servers-gs.sh
index 02e7c7f..8bb5338 100755
--- a/tuts/008-vpc-private-servers-gs/vpc-private-servers-gs.sh
+++ b/tuts/008-vpc-private-servers-gs/vpc-private-servers-gs.sh
@@ -184,7 +184,7 @@ echo "Using random identifier: $RANDOM_ID"
# Create VPC
echo "Creating VPC..."
-VPC_RESULT=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=ProductionVPC-$RANDOM_ID}]")
+VPC_RESULT=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=ProductionVPC-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create VPC"
VPC_ID=$(echo "$VPC_RESULT" | jq -r '.Vpc.VpcId')
@@ -203,19 +203,19 @@ echo "Using Availability Zones: $AZ1 and $AZ2"
# Create subnets
echo "Creating subnets..."
-PUBLIC_SUBNET1_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.0.0/24 --availability-zone "$AZ1" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet1-$RANDOM_ID}]")
+PUBLIC_SUBNET1_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.0.0/24 --availability-zone "$AZ1" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet1-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create public subnet 1"
PUBLIC_SUBNET1_ID=$(echo "$PUBLIC_SUBNET1_RESULT" | jq -r '.Subnet.SubnetId')
-PRIVATE_SUBNET1_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.0/24 --availability-zone "$AZ1" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet1-$RANDOM_ID}]")
+PRIVATE_SUBNET1_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.0/24 --availability-zone "$AZ1" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet1-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create private subnet 1"
PRIVATE_SUBNET1_ID=$(echo "$PRIVATE_SUBNET1_RESULT" | jq -r '.Subnet.SubnetId')
-PUBLIC_SUBNET2_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.2.0/24 --availability-zone "$AZ2" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet2-$RANDOM_ID}]")
+PUBLIC_SUBNET2_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.2.0/24 --availability-zone "$AZ2" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet2-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create public subnet 2"
PUBLIC_SUBNET2_ID=$(echo "$PUBLIC_SUBNET2_RESULT" | jq -r '.Subnet.SubnetId')
-PRIVATE_SUBNET2_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.3.0/24 --availability-zone "$AZ2" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet2-$RANDOM_ID}]")
+PRIVATE_SUBNET2_RESULT=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.3.0/24 --availability-zone "$AZ2" --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet2-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create private subnet 2"
PRIVATE_SUBNET2_ID=$(echo "$PRIVATE_SUBNET2_RESULT" | jq -r '.Subnet.SubnetId')
@@ -227,7 +227,7 @@ echo "Private Subnet 2: $PRIVATE_SUBNET2_ID"
# Create Internet Gateway
echo "Creating Internet Gateway..."
-IGW_RESULT=$(aws ec2 create-internet-gateway --tag-specifications "ResourceType=internet-gateway,Tags=[{Key=Name,Value=ProductionIGW-$RANDOM_ID}]")
+IGW_RESULT=$(aws ec2 create-internet-gateway --tag-specifications "ResourceType=internet-gateway,Tags=[{Key=Name,Value=ProductionIGW-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create Internet Gateway"
IGW_ID=$(echo "$IGW_RESULT" | jq -r '.InternetGateway.InternetGatewayId')
echo "Internet Gateway created with ID: $IGW_ID"
@@ -239,15 +239,15 @@ check_command "Failed to attach Internet Gateway to VPC"
# Create route tables
echo "Creating route tables..."
-PUBLIC_RT_RESULT=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=PublicRouteTable-$RANDOM_ID}]")
+PUBLIC_RT_RESULT=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=PublicRouteTable-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create public route table"
PUBLIC_RT_ID=$(echo "$PUBLIC_RT_RESULT" | jq -r '.RouteTable.RouteTableId')
-PRIVATE_RT1_RESULT=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=PrivateRouteTable1-$RANDOM_ID}]")
+PRIVATE_RT1_RESULT=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=PrivateRouteTable1-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create private route table 1"
PRIVATE_RT1_ID=$(echo "$PRIVATE_RT1_RESULT" | jq -r '.RouteTable.RouteTableId')
-PRIVATE_RT2_RESULT=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=PrivateRouteTable2-$RANDOM_ID}]")
+PRIVATE_RT2_RESULT=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=PrivateRouteTable2-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create private route table 2"
PRIVATE_RT2_ID=$(echo "$PRIVATE_RT2_RESULT" | jq -r '.RouteTable.RouteTableId')
@@ -290,11 +290,11 @@ echo "Creating NAT Gateways..."
# Allocate Elastic IPs for NAT Gateways
echo "Allocating Elastic IPs for NAT Gateways..."
-EIP1_RESULT=$(aws ec2 allocate-address --domain vpc --tag-specifications "ResourceType=elastic-ip,Tags=[{Key=Name,Value=NAT1-EIP-$RANDOM_ID}]")
+EIP1_RESULT=$(aws ec2 allocate-address --domain vpc --tag-specifications "ResourceType=elastic-ip,Tags=[{Key=Name,Value=NAT1-EIP-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to allocate Elastic IP 1"
EIP1_ALLOC_ID=$(echo "$EIP1_RESULT" | jq -r '.AllocationId')
-EIP2_RESULT=$(aws ec2 allocate-address --domain vpc --tag-specifications "ResourceType=elastic-ip,Tags=[{Key=Name,Value=NAT2-EIP-$RANDOM_ID}]")
+EIP2_RESULT=$(aws ec2 allocate-address --domain vpc --tag-specifications "ResourceType=elastic-ip,Tags=[{Key=Name,Value=NAT2-EIP-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to allocate Elastic IP 2"
EIP2_ALLOC_ID=$(echo "$EIP2_RESULT" | jq -r '.AllocationId')
@@ -304,12 +304,12 @@ echo "EIP 2 Allocation ID: $EIP2_ALLOC_ID"
# Create NAT Gateways
echo "Creating NAT Gateway in public subnet 1..."
-NAT_GW1_RESULT=$(aws ec2 create-nat-gateway --subnet-id "$PUBLIC_SUBNET1_ID" --allocation-id "$EIP1_ALLOC_ID" --tag-specifications "ResourceType=natgateway,Tags=[{Key=Name,Value=NAT-Gateway1-$RANDOM_ID}]")
+NAT_GW1_RESULT=$(aws ec2 create-nat-gateway --subnet-id "$PUBLIC_SUBNET1_ID" --allocation-id "$EIP1_ALLOC_ID" --tag-specifications "ResourceType=natgateway,Tags=[{Key=Name,Value=NAT-Gateway1-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create NAT Gateway 1"
NAT_GW1_ID=$(echo "$NAT_GW1_RESULT" | jq -r '.NatGateway.NatGatewayId')
echo "Creating NAT Gateway in public subnet 2..."
-NAT_GW2_RESULT=$(aws ec2 create-nat-gateway --subnet-id "$PUBLIC_SUBNET2_ID" --allocation-id "$EIP2_ALLOC_ID" --tag-specifications "ResourceType=natgateway,Tags=[{Key=Name,Value=NAT-Gateway2-$RANDOM_ID}]")
+NAT_GW2_RESULT=$(aws ec2 create-nat-gateway --subnet-id "$PUBLIC_SUBNET2_ID" --allocation-id "$EIP2_ALLOC_ID" --tag-specifications "ResourceType=natgateway,Tags=[{Key=Name,Value=NAT-Gateway2-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create NAT Gateway 2"
NAT_GW2_ID=$(echo "$NAT_GW2_RESULT" | jq -r '.NatGateway.NatGatewayId')
@@ -338,14 +338,14 @@ echo "Creating VPC Endpoint for S3..."
S3_PREFIX_LIST_ID=$(aws ec2 describe-prefix-lists --filters "Name=prefix-list-name,Values=com.amazonaws.$(aws configure get region).s3" --query 'PrefixLists[0].PrefixListId' --output text)
check_command "Failed to get S3 prefix list ID"
-VPC_ENDPOINT_RESULT=$(aws ec2 create-vpc-endpoint --vpc-id "$VPC_ID" --service-name "com.amazonaws.$(aws configure get region).s3" --route-table-ids "$PRIVATE_RT1_ID" "$PRIVATE_RT2_ID" --tag-specifications "ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=S3-Endpoint-$RANDOM_ID}]")
+VPC_ENDPOINT_RESULT=$(aws ec2 create-vpc-endpoint --vpc-id "$VPC_ID" --service-name "com.amazonaws.$(aws configure get region).s3" --route-table-ids "$PRIVATE_RT1_ID" "$PRIVATE_RT2_ID" --tag-specifications "ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=S3-Endpoint-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create VPC endpoint for S3"
VPC_ENDPOINT_ID=$(echo "$VPC_ENDPOINT_RESULT" | jq -r '.VpcEndpoint.VpcEndpointId')
echo "VPC Endpoint created with ID: $VPC_ENDPOINT_ID"
# Create security groups
echo "Creating security groups..."
-LB_SG_RESULT=$(aws ec2 create-security-group --group-name "LoadBalancerSG-$RANDOM_ID" --description "Security group for the load balancer" --vpc-id "$VPC_ID" --tag-specifications "ResourceType=security-group,Tags=[{Key=Name,Value=LoadBalancerSG-$RANDOM_ID}]")
+LB_SG_RESULT=$(aws ec2 create-security-group --group-name "LoadBalancerSG-$RANDOM_ID" --description "Security group for the load balancer" --vpc-id "$VPC_ID" --tag-specifications "ResourceType=security-group,Tags=[{Key=Name,Value=LoadBalancerSG-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create load balancer security group"
LB_SG_ID=$(echo "$LB_SG_RESULT" | jq -r '.GroupId')
@@ -353,7 +353,7 @@ LB_SG_ID=$(echo "$LB_SG_RESULT" | jq -r '.GroupId')
aws ec2 authorize-security-group-ingress --group-id "$LB_SG_ID" --protocol tcp --port 80 --cidr 0.0.0.0/0
check_command "Failed to authorize ingress to load balancer security group"
-APP_SG_RESULT=$(aws ec2 create-security-group --group-name "AppServerSG-$RANDOM_ID" --description "Security group for the application servers" --vpc-id "$VPC_ID" --tag-specifications "ResourceType=security-group,Tags=[{Key=Name,Value=AppServerSG-$RANDOM_ID}]")
+APP_SG_RESULT=$(aws ec2 create-security-group --group-name "AppServerSG-$RANDOM_ID" --description "Security group for the application servers" --vpc-id "$VPC_ID" --tag-specifications "ResourceType=security-group,Tags=[{Key=Name,Value=AppServerSG-$RANDOM_ID},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]")
check_command "Failed to create application server security group"
APP_SG_ID=$(echo "$APP_SG_RESULT" | jq -r '.GroupId')
@@ -400,7 +400,7 @@ echo "Creating launch template: $LAUNCH_TEMPLATE_NAME"
aws ec2 create-launch-template \
--launch-template-name "$LAUNCH_TEMPLATE_NAME" \
--version-description "Initial version" \
- --tag-specifications "ResourceType=launch-template,Tags=[{Key=Name,Value=$LAUNCH_TEMPLATE_NAME}]" \
+ --tag-specifications "ResourceType=launch-template,Tags=[{Key=Name,Value=$LAUNCH_TEMPLATE_NAME},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-private-servers-gs}]" \
--launch-template-data "{
\"NetworkInterfaces\": [{
\"DeviceIndex\": 0,
@@ -435,7 +435,8 @@ TARGET_GROUP_RESULT=$(aws elbv2 create-target-group \
--target-type instance \
--health-check-protocol HTTP \
--health-check-path "/" \
- --health-check-port traffic-port)
+ --health-check-port traffic-port \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=vpc-private-servers-gs)
check_command "Failed to create target group"
TARGET_GROUP_ARN=$(echo "$TARGET_GROUP_RESULT" | jq -r '.TargetGroups[0].TargetGroupArn')
echo "Target group created with ARN: $TARGET_GROUP_ARN"
@@ -447,7 +448,7 @@ LB_RESULT=$(aws elbv2 create-load-balancer \
--name "$LB_NAME" \
--subnets "$PUBLIC_SUBNET1_ID" "$PUBLIC_SUBNET2_ID" \
--security-groups "$LB_SG_ID" \
- --tags "Key=Name,Value=$LB_NAME")
+ --tags "Key=Name,Value=$LB_NAME" Key=project,Value=doc-smith Key=tutorial,Value=vpc-private-servers-gs)
check_command "Failed to create load balancer"
LB_ARN=$(echo "$LB_RESULT" | jq -r '.LoadBalancers[0].LoadBalancerArn')
echo "Load balancer created with ARN: $LB_ARN"
@@ -481,7 +482,7 @@ aws autoscaling create-auto-scaling-group \
--target-group-arns "$TARGET_GROUP_ARN" \
--health-check-type ELB \
--health-check-grace-period 300 \
- --tags "Key=Name,Value=AppServer-$RANDOM_ID,PropagateAtLaunch=true"
+ --tags "Key=Name,Value=AppServer-$RANDOM_ID,PropagateAtLaunch=true" Key=project,Value=doc-smith,PropagateAtLaunch=true Key=tutorial,Value=vpc-private-servers-gs,PropagateAtLaunch=true
check_command "Failed to create Auto Scaling group"
echo "Auto Scaling group created with name: $ASG_NAME"
diff --git a/tuts/009-vpc-ipam-gs/vpc-ipam-gs.sh b/tuts/009-vpc-ipam-gs/vpc-ipam-gs.sh
index d0e261e..a9113a5 100755
--- a/tuts/009-vpc-ipam-gs/vpc-ipam-gs.sh
+++ b/tuts/009-vpc-ipam-gs/vpc-ipam-gs.sh
@@ -179,7 +179,8 @@ wait_for_cidr_provisioning() {
echo "Creating IPAM..."
IPAM_RESULT=$(aws ec2 create-ipam \
--description "My IPAM" \
- --operating-regions RegionName=us-east-1 RegionName=us-west-2)
+ --operating-regions RegionName=us-east-1 RegionName=us-west-2 \
+ --tag-specifications 'ResourceType=ipam,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-ipam-gs}]')
if [ $? -ne 0 ]; then
handle_error "Failed to create IPAM"
@@ -213,7 +214,8 @@ echo "Creating Top-level IPv4 Pool..."
TOP_POOL_RESULT=$(aws ec2 create-ipam-pool \
--ipam-scope-id "$PRIVATE_SCOPE_ID" \
--address-family ipv4 \
- --description "Top-level pool")
+ --description "Top-level pool" \
+ --tag-specifications 'ResourceType=ipam-pool,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-ipam-gs}]')
if [ $? -ne 0 ]; then
handle_error "Failed to create Top-level Pool"
@@ -252,7 +254,8 @@ REGIONAL_POOL_RESULT=$(aws ec2 create-ipam-pool \
--source-ipam-pool-id "$TOP_POOL_ID" \
--locale us-east-1 \
--address-family ipv4 \
- --description "Regional pool in us-east-1")
+ --description "Regional pool in us-east-1" \
+ --tag-specifications 'ResourceType=ipam-pool,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-ipam-gs}]')
if [ $? -ne 0 ]; then
handle_error "Failed to create Regional Pool"
@@ -291,7 +294,8 @@ DEV_POOL_RESULT=$(aws ec2 create-ipam-pool \
--source-ipam-pool-id "$REGIONAL_POOL_ID" \
--locale us-east-1 \
--address-family ipv4 \
- --description "Development pool")
+ --description "Development pool" \
+ --tag-specifications 'ResourceType=ipam-pool,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-ipam-gs}]')
if [ $? -ne 0 ]; then
handle_error "Failed to create Development Pool"
@@ -328,7 +332,7 @@ echo "Creating VPC using IPAM Pool CIDR..."
VPC_RESULT=$(aws ec2 create-vpc \
--ipv4-ipam-pool-id "$DEV_POOL_ID" \
--ipv4-netmask-length 26 \
- --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=IPAM-VPC}]')
+ --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=IPAM-VPC},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-ipam-gs}]')
if [ $? -ne 0 ]; then
handle_error "Failed to create VPC"
diff --git a/tuts/010-cloudmap-service-discovery/cloudmap-service-discovery.sh b/tuts/010-cloudmap-service-discovery/cloudmap-service-discovery.sh
index 38474b0..01ad920 100755
--- a/tuts/010-cloudmap-service-discovery/cloudmap-service-discovery.sh
+++ b/tuts/010-cloudmap-service-discovery/cloudmap-service-discovery.sh
@@ -101,6 +101,7 @@ log "Creating AWS Cloud Map namespace: $NAMESPACE_NAME"
OPERATION_RESULT=$(aws servicediscovery create-public-dns-namespace \
--name "$NAMESPACE_NAME" \
--creator-request-id "cloudmap-tutorial-$CREATOR_REQUEST_ID" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-service-discovery \
--region "$REGION")
OPERATION_ID=$(echo "$OPERATION_RESULT" | jq -r '.OperationId')
@@ -133,6 +134,7 @@ PUBLIC_SERVICE_RESULT=$(aws servicediscovery create-service \
--name "public-service" \
--namespace-id "$NAMESPACE_ID" \
--dns-config "RoutingPolicy=MULTIVALUE,DnsRecords=[{Type=A,TTL=300}]" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-service-discovery \
--region "$REGION")
PUBLIC_SERVICE_ID=$(echo "$PUBLIC_SERVICE_RESULT" | jq -r '.Service.Id')
@@ -143,6 +145,7 @@ BACKEND_SERVICE_RESULT=$(aws servicediscovery create-service \
--name "backend-service" \
--namespace-id "$NAMESPACE_ID" \
--type "HTTP" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudmap-service-discovery \
--region "$REGION")
BACKEND_SERVICE_ID=$(echo "$BACKEND_SERVICE_RESULT" | jq -r '.Service.Id')
diff --git a/tuts/011-getting-started-batch-fargate/getting-started-batch-fargate.sh b/tuts/011-getting-started-batch-fargate/getting-started-batch-fargate.sh
index 9e24f22..ebb8460 100644
--- a/tuts/011-getting-started-batch-fargate/getting-started-batch-fargate.sh
+++ b/tuts/011-getting-started-batch-fargate/getting-started-batch-fargate.sh
@@ -364,6 +364,7 @@ EOFPOLICY
aws iam create-role \
--role-name "${ROLE_NAME}" \
--assume-role-policy-document "file://${TRUST_POLICY_FILE}"
+ aws iam tag-role --role-name "${ROLE_NAME}" --tags Key=project,Value=doc-smith Key=tutorial,Value=getting-started-batch-fargate
CREATED_RESOURCES+=("IAM_ROLE:${ROLE_NAME}")
# Attach policy
@@ -384,6 +385,7 @@ EOFPOLICY
--compute-environment-name "${COMPUTE_ENV_NAME}" \
--type MANAGED \
--state ENABLED \
+ --tags project=doc-smith,tutorial=getting-started-batch-fargate \
--compute-resources "{
\"type\": \"FARGATE\",
\"maxvCpus\": 256,
@@ -405,6 +407,7 @@ EOFPOLICY
--job-queue-name "${JOB_QUEUE_NAME}" \
--state ENABLED \
--priority 900 \
+ --tags project=doc-smith,tutorial=getting-started-batch-fargate \
--compute-environment-order "order=1,computeEnvironment=${COMPUTE_ENV_NAME}"
CREATED_RESOURCES+=("JOB_QUEUE:${JOB_QUEUE_NAME}")
diff --git a/tuts/012-transitgateway-gettingstarted/transitgateway-gettingstarted.sh b/tuts/012-transitgateway-gettingstarted/transitgateway-gettingstarted.sh
index 57b7a13..292f0d3 100644
--- a/tuts/012-transitgateway-gettingstarted/transitgateway-gettingstarted.sh
+++ b/tuts/012-transitgateway-gettingstarted/transitgateway-gettingstarted.sh
@@ -201,7 +201,7 @@ if [ "$VPC1_ID" = "None" ] || [ -z "$VPC1_ID" ]; then
echo "Creating VPC1..."
VPC1_ID=$(aws ec2 create-vpc \
--cidr-block 10.1.0.0/16 \
- --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC1}]' \
+ --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC1},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query Vpc.VpcId \
--output text)
validate_aws_output "$VPC1_ID" "VPC1" || exit 1
@@ -213,7 +213,7 @@ if [ "$VPC1_ID" = "None" ] || [ -z "$VPC1_ID" ]; then
--vpc-id "$VPC1_ID" \
--cidr-block 10.1.0.0/24 \
--availability-zone "$AZ" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC1-Subnet}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC1-Subnet},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query Subnet.SubnetId \
--output text)
validate_aws_output "$SUBNET1_ID" "VPC1 subnet" || exit 1
@@ -230,7 +230,7 @@ else
--vpc-id "$VPC1_ID" \
--cidr-block 10.1.0.0/24 \
--availability-zone "$AZ" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC1-Subnet}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC1-Subnet},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query Subnet.SubnetId \
--output text)
validate_aws_output "$SUBNET1_ID" "VPC1 subnet" || exit 1
@@ -244,7 +244,7 @@ if [ "$VPC2_ID" = "None" ] || [ -z "$VPC2_ID" ]; then
echo "Creating VPC2..."
VPC2_ID=$(aws ec2 create-vpc \
--cidr-block 10.2.0.0/16 \
- --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC2}]' \
+ --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC2},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query Vpc.VpcId \
--output text)
validate_aws_output "$VPC2_ID" "VPC2" || exit 1
@@ -256,7 +256,7 @@ if [ "$VPC2_ID" = "None" ] || [ -z "$VPC2_ID" ]; then
--vpc-id "$VPC2_ID" \
--cidr-block 10.2.0.0/24 \
--availability-zone "$AZ" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC2-Subnet}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC2-Subnet},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query Subnet.SubnetId \
--output text)
validate_aws_output "$SUBNET2_ID" "VPC2 subnet" || exit 1
@@ -273,7 +273,7 @@ else
--vpc-id "$VPC2_ID" \
--cidr-block 10.2.0.0/24 \
--availability-zone "$AZ" \
- --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC2-Subnet}]' \
+ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC2-Subnet},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query Subnet.SubnetId \
--output text)
validate_aws_output "$SUBNET2_ID" "VPC2 subnet" || exit 1
@@ -304,7 +304,7 @@ echo "Creating Transit Gateway..."
TGW_ID=$(aws ec2 create-transit-gateway \
--description "My Transit Gateway" \
--options "AmazonSideAsn=64512,AutoAcceptSharedAttachments=disable,DefaultRouteTableAssociation=enable,DefaultRouteTablePropagation=enable,VpnEcmpSupport=enable,DnsSupport=enable,MulticastSupport=disable" \
- --tag-specifications 'ResourceType=transit-gateway,Tags=[{Key=Name,Value=MyTransitGateway}]' \
+ --tag-specifications 'ResourceType=transit-gateway,Tags=[{Key=Name,Value=MyTransitGateway},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query TransitGateway.TransitGatewayId \
--output text)
validate_aws_output "$TGW_ID" "Transit Gateway" || exit 1
@@ -319,7 +319,7 @@ TGW_ATTACHMENT_1_ID=$(aws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id "$TGW_ID" \
--vpc-id "$VPC1_ID" \
--subnet-ids "$SUBNET1_ID" \
- --tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=VPC1-Attachment}]' \
+ --tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=VPC1-Attachment},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query TransitGatewayVpcAttachment.TransitGatewayAttachmentId \
--output text)
validate_aws_output "$TGW_ATTACHMENT_1_ID" "Transit Gateway VPC1 Attachment" || exit 1
@@ -330,7 +330,7 @@ TGW_ATTACHMENT_2_ID=$(aws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id "$TGW_ID" \
--vpc-id "$VPC2_ID" \
--subnet-ids "$SUBNET2_ID" \
- --tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=VPC2-Attachment}]' \
+ --tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=VPC2-Attachment},{Key=project,Value=doc-smith},{Key=tutorial,Value=transitgateway-gettingstarted}]' \
--query TransitGatewayVpcAttachment.TransitGatewayAttachmentId \
--output text)
validate_aws_output "$TGW_ATTACHMENT_2_ID" "Transit Gateway VPC2 Attachment" || exit 1
diff --git a/tuts/013-ec2-basics/ec2-basics.sh b/tuts/013-ec2-basics/ec2-basics.sh
old mode 100755
new mode 100644
index 21796e0..554e8ee
--- a/tuts/013-ec2-basics/ec2-basics.sh
+++ b/tuts/013-ec2-basics/ec2-basics.sh
@@ -155,6 +155,7 @@ log "Creating security group..."
SECURITY_GROUP_ID=$(aws ec2 create-security-group \
--group-name "$SG_NAME" \
--description "Security group for EC2 tutorial" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=ec2-basics}]' \
--query "GroupId" \
--output text)
@@ -224,6 +225,7 @@ INSTANCE_ID=$(aws ec2 run-instances \
--security-group-ids "$SECURITY_GROUP_ID" \
--metadata-options "HttpTokens=required,HttpEndpoint=enabled" \
--block-device-mappings "DeviceName=/dev/xvda,Ebs={Encrypted=true}" \
+ --tag-specifications 'ResourceType=instance,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=ec2-basics}]' 'ResourceType=volume,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=ec2-basics}]' \
--count 1 \
--query 'Instances[0].InstanceId' \
--output text)
@@ -306,6 +308,7 @@ log "To connect to your instance, run: ssh -i $KEY_FILE ec2-user@$NEW_PUBLIC_IP"
log "Allocating Elastic IP address..."
ALLOCATION_RESULT=$(aws ec2 allocate-address \
--domain vpc \
+ --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=ec2-basics}]' \
--query '[PublicIp,AllocationId]' \
--output text)
@@ -385,4 +388,4 @@ log "To connect to your instance, run: ssh -i $KEY_FILE ec2-user@$ELASTIC_IP"
log "Tutorial completed successfully!"
cleanup
-exit 0
+exit 0
\ No newline at end of file
diff --git a/tuts/015-vpc-peering/vpc-peering.sh b/tuts/015-vpc-peering/vpc-peering.sh
index 7652049..b32d46e 100644
--- a/tuts/015-vpc-peering/vpc-peering.sh
+++ b/tuts/015-vpc-peering/vpc-peering.sh
@@ -166,71 +166,91 @@ echo "Setting up VPC peering connection..."
# Validate AWS CLI
validate_aws_cli
-# Check VPC quota — need room for up to 2 new VPCs
-VPC_COUNT=$(aws ec2 describe-vpcs --region "$AWS_REGION" --query 'length(Vpcs)' --output text 2>/dev/null || echo 99)
-VPC_LIMIT=5
-VPCS_NEEDED=2
-
-# Check if prereq stack provides a VPC we can use as VPC1
-PREREQ_VPC_ID=""
-PREREQ_STACK=$(aws cloudformation describe-stacks --region "$AWS_REGION" --stack-name tutorial-prereqs-vpc-public --query 'Stacks[0].StackStatus' --output text 2>/dev/null || echo "")
-if [[ "$PREREQ_STACK" == "CREATE_COMPLETE" || "$PREREQ_STACK" == "UPDATE_COMPLETE" ]]; then
- PREREQ_VPC_ID=$(aws cloudformation describe-stacks --region "$AWS_REGION" --stack-name tutorial-prereqs-vpc-public --query 'Stacks[0].Outputs[?OutputKey==`VpcId`].OutputValue' --output text 2>/dev/null || echo "")
- if [ -n "$PREREQ_VPC_ID" ]; then
- echo "Found prereq stack VPC: $PREREQ_VPC_ID (10.0.0.0/16)"
- VPCS_NEEDED=1
- fi
-fi
+# Check for existing VPCs
+echo "Checking for existing VPCs..."
+EXISTING_VPCS=$(aws ec2 describe-vpcs --region "$AWS_REGION" --query 'Vpcs[?State==`available`].[VpcId,CidrBlock]' --output text 2>/dev/null || echo "")
-AVAILABLE=$((VPC_LIMIT - VPC_COUNT))
-if [ "$AVAILABLE" -lt "$VPCS_NEEDED" ]; then
- echo "ERROR: Need $VPCS_NEEDED VPC slots but only $AVAILABLE available ($VPC_COUNT/$VPC_LIMIT used in $AWS_REGION)."
- echo "Free up VPCs or run in a different region: AWS_REGION= bash $0"
- exit 1
+if [ -z "$EXISTING_VPCS" ]; then
+ echo "No existing VPCs found. Creating new VPCs..."
+ CREATE_VPCS=true
+else
+ echo "Found existing VPCs:"
+ echo "$EXISTING_VPCS"
+ echo ""
+ echo "Using existing VPCs..."
+ CREATE_VPCS=false
+ # Get the first two available VPCs
+ VPC1_INFO=$(echo "$EXISTING_VPCS" | head -n 1)
+ VPC2_INFO=$(echo "$EXISTING_VPCS" | head -n 2 | tail -n 1)
+
+ if [ -z "$VPC2_INFO" ]; then
+ echo "Only one VPC found. Creating a second VPC..."
+ VPC1_ID=$(echo "$VPC1_INFO" | awk '{print $1}')
+ VPC1_CIDR=$(echo "$VPC1_INFO" | awk '{print $2}')
+
+ # Sanitize extracted values
+ VPC1_ID=$(sanitize_var "$VPC1_ID") || check_error 1 "Invalid VPC1_ID format"
+ VPC1_CIDR=$(sanitize_var "$VPC1_CIDR") || check_error 1 "Invalid VPC1_CIDR format"
+
+ validate_cidr "$VPC1_CIDR" || check_error 1 "Invalid VPC1 CIDR"
+ CREATE_VPC2_ONLY=true
+ else
+ VPC1_ID=$(echo "$VPC1_INFO" | awk '{print $1}')
+ VPC1_CIDR=$(echo "$VPC1_INFO" | awk '{print $2}')
+ VPC2_ID=$(echo "$VPC2_INFO" | awk '{print $1}')
+ VPC2_CIDR=$(echo "$VPC2_INFO" | awk '{print $2}')
+
+ # Sanitize extracted values
+ VPC1_ID=$(sanitize_var "$VPC1_ID") || check_error 1 "Invalid VPC1_ID format"
+ VPC1_CIDR=$(sanitize_var "$VPC1_CIDR") || check_error 1 "Invalid VPC1_CIDR format"
+ VPC2_ID=$(sanitize_var "$VPC2_ID") || check_error 1 "Invalid VPC2_ID format"
+ VPC2_CIDR=$(sanitize_var "$VPC2_CIDR") || check_error 1 "Invalid VPC2_CIDR format"
+
+ validate_cidr "$VPC1_CIDR" || check_error 1 "Invalid VPC1 CIDR"
+ validate_cidr "$VPC2_CIDR" || check_error 1 "Invalid VPC2 CIDR"
+ CREATE_VPC2_ONLY=false
+ fi
fi
-# Set up VPCs
-if [ -n "$PREREQ_VPC_ID" ]; then
- # Use prereq VPC as VPC1, create VPC2
- VPC1_ID="$PREREQ_VPC_ID"
- VPC1_CIDR="10.0.0.0/16"
- echo "Using prereq stack VPC as VPC1: $VPC1_ID ($VPC1_CIDR)"
-
- echo "Creating VPC2..."
- VPC2_ID=$(log_cmd "aws ec2 create-vpc --region '$AWS_REGION' --cidr-block 10.2.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC2-Peering-Demo}]' --query 'Vpc.VpcId' --output text")
- check_error $? "Failed to create VPC2"
- VPC2_ID=$(sanitize_var "$VPC2_ID") || check_error 1 "Invalid VPC2_ID returned"
- VPC2_CIDR="10.2.0.0/16"
- CREATED_RESOURCES+=("VPC2: $VPC2_ID")
- CLEANUP_COMMANDS+=("aws ec2 delete-vpc --region '$AWS_REGION' --vpc-id '$VPC2_ID'")
- echo "VPC2 created with ID: $VPC2_ID"
-
- echo "Waiting for VPC2 to be available..."
- log_cmd "aws ec2 wait vpc-available --region '$AWS_REGION' --vpc-ids '$VPC2_ID'"
- check_error $? "Timeout waiting for VPC2 to become available"
-else
- # Create both VPCs
+# Create VPCs if needed
+if [ "$CREATE_VPCS" = true ]; then
echo "Creating VPC1..."
- VPC1_ID=$(log_cmd "aws ec2 create-vpc --region '$AWS_REGION' --cidr-block 10.1.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC1-Peering-Demo}]' --query 'Vpc.VpcId' --output text")
+ VPC1_ID=$(log_cmd "aws ec2 create-vpc --region '$AWS_REGION' --cidr-block 10.1.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC1-Peering-Demo},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'Vpc.VpcId' --output text")
check_error $? "Failed to create VPC1"
VPC1_ID=$(sanitize_var "$VPC1_ID") || check_error 1 "Invalid VPC1_ID returned"
VPC1_CIDR="10.1.0.0/16"
CREATED_RESOURCES+=("VPC1: $VPC1_ID")
CLEANUP_COMMANDS+=("aws ec2 delete-vpc --region '$AWS_REGION' --vpc-id '$VPC1_ID'")
echo "VPC1 created with ID: $VPC1_ID"
-
+
echo "Creating VPC2..."
- VPC2_ID=$(log_cmd "aws ec2 create-vpc --region '$AWS_REGION' --cidr-block 10.2.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC2-Peering-Demo}]' --query 'Vpc.VpcId' --output text")
+ VPC2_ID=$(log_cmd "aws ec2 create-vpc --region '$AWS_REGION' --cidr-block 10.2.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC2-Peering-Demo},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'Vpc.VpcId' --output text")
check_error $? "Failed to create VPC2"
VPC2_ID=$(sanitize_var "$VPC2_ID") || check_error 1 "Invalid VPC2_ID returned"
VPC2_CIDR="10.2.0.0/16"
CREATED_RESOURCES+=("VPC2: $VPC2_ID")
CLEANUP_COMMANDS+=("aws ec2 delete-vpc --region '$AWS_REGION' --vpc-id '$VPC2_ID'")
echo "VPC2 created with ID: $VPC2_ID"
-
+
+ # Wait for VPCs to be available
echo "Waiting for VPCs to be available..."
log_cmd "aws ec2 wait vpc-available --region '$AWS_REGION' --vpc-ids '$VPC1_ID' '$VPC2_ID'"
check_error $? "Timeout waiting for VPCs to become available"
+
+elif [ "$CREATE_VPC2_ONLY" = true ]; then
+ echo "Creating VPC2..."
+ VPC2_ID=$(log_cmd "aws ec2 create-vpc --region '$AWS_REGION' --cidr-block 10.2.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC2-Peering-Demo},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'Vpc.VpcId' --output text")
+ check_error $? "Failed to create VPC2"
+ VPC2_ID=$(sanitize_var "$VPC2_ID") || check_error 1 "Invalid VPC2_ID returned"
+ VPC2_CIDR="10.2.0.0/16"
+ CREATED_RESOURCES+=("VPC2: $VPC2_ID")
+ CLEANUP_COMMANDS+=("aws ec2 delete-vpc --region '$AWS_REGION' --vpc-id '$VPC2_ID'")
+ echo "VPC2 created with ID: $VPC2_ID"
+
+ # Wait for VPC2 to be available
+ echo "Waiting for VPC2 to be available..."
+ log_cmd "aws ec2 wait vpc-available --region '$AWS_REGION' --vpc-ids '$VPC2_ID'"
+ check_error $? "Timeout waiting for VPC2 to become available"
fi
echo "Using the following VPCs:"
@@ -243,9 +263,8 @@ log_cmd "aws ec2 describe-vpcs --region '$AWS_REGION' --vpc-ids '$VPC1_ID' '$VPC
check_error $? "Failed to verify VPCs"
# Determine subnet CIDR blocks based on VPC CIDR blocks
-# Use .100.0/24 to avoid overlap with prereq stack subnets (.1-.4)
-VPC1_SUBNET_CIDR=$(echo "$VPC1_CIDR" | sed 's/0\.0\/16/100.0\/24/')
-VPC2_SUBNET_CIDR=$(echo "$VPC2_CIDR" | sed 's/0\.0\/16/100.0\/24/')
+VPC1_SUBNET_CIDR=$(echo "$VPC1_CIDR" | sed 's/0\.0\/16/1.0\/24/')
+VPC2_SUBNET_CIDR=$(echo "$VPC2_CIDR" | sed 's/0\.0\/16/1.0\/24/')
# Sanitize subnet CIDR blocks
VPC1_SUBNET_CIDR=$(sanitize_var "$VPC1_SUBNET_CIDR") || check_error 1 "Invalid VPC1_SUBNET_CIDR format"
@@ -256,7 +275,7 @@ validate_cidr "$VPC2_SUBNET_CIDR" || check_error 1 "Invalid subnet CIDR for VPC2
# Create subnets in both VPCs
echo "Creating subnet in VPC1..."
-SUBNET1_ID=$(log_cmd "aws ec2 create-subnet --region '$AWS_REGION' --vpc-id '$VPC1_ID' --cidr-block '$VPC1_SUBNET_CIDR' --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC1-Peering-Subnet}]' --query 'Subnet.SubnetId' --output text")
+SUBNET1_ID=$(log_cmd "aws ec2 create-subnet --region '$AWS_REGION' --vpc-id '$VPC1_ID' --cidr-block '$VPC1_SUBNET_CIDR' --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC1-Peering-Subnet},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'Subnet.SubnetId' --output text")
check_error $? "Failed to create subnet in VPC1"
SUBNET1_ID=$(sanitize_var "$SUBNET1_ID") || check_error 1 "Invalid SUBNET1_ID returned"
CREATED_RESOURCES+=("Subnet in VPC1: $SUBNET1_ID")
@@ -264,7 +283,7 @@ CLEANUP_COMMANDS+=("aws ec2 delete-subnet --region '$AWS_REGION' --subnet-id '$S
echo "Subnet created in VPC1 with ID: $SUBNET1_ID (CIDR: $VPC1_SUBNET_CIDR)"
echo "Creating subnet in VPC2..."
-SUBNET2_ID=$(log_cmd "aws ec2 create-subnet --region '$AWS_REGION' --vpc-id '$VPC2_ID' --cidr-block '$VPC2_SUBNET_CIDR' --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC2-Peering-Subnet}]' --query 'Subnet.SubnetId' --output text")
+SUBNET2_ID=$(log_cmd "aws ec2 create-subnet --region '$AWS_REGION' --vpc-id '$VPC2_ID' --cidr-block '$VPC2_SUBNET_CIDR' --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=VPC2-Peering-Subnet},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'Subnet.SubnetId' --output text")
check_error $? "Failed to create subnet in VPC2"
SUBNET2_ID=$(sanitize_var "$SUBNET2_ID") || check_error 1 "Invalid SUBNET2_ID returned"
CREATED_RESOURCES+=("Subnet in VPC2: $SUBNET2_ID")
@@ -273,7 +292,7 @@ echo "Subnet created in VPC2 with ID: $SUBNET2_ID (CIDR: $VPC2_SUBNET_CIDR)"
# Create a VPC peering connection
echo "Creating VPC peering connection..."
-PEERING_ID=$(log_cmd "aws ec2 create-vpc-peering-connection --region '$AWS_REGION' --vpc-id '$VPC1_ID' --peer-vpc-id '$VPC2_ID' --tag-specifications 'ResourceType=vpc-peering-connection,Tags=[{Key=Name,Value=VPC1-VPC2-Peering}]' --query 'VpcPeeringConnection.VpcPeeringConnectionId' --output text")
+PEERING_ID=$(log_cmd "aws ec2 create-vpc-peering-connection --region '$AWS_REGION' --vpc-id '$VPC1_ID' --peer-vpc-id '$VPC2_ID' --tag-specifications 'ResourceType=vpc-peering-connection,Tags=[{Key=Name,Value=VPC1-VPC2-Peering},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'VpcPeeringConnection.VpcPeeringConnectionId' --output text")
check_error $? "Failed to create VPC peering connection"
PEERING_ID=$(sanitize_var "$PEERING_ID") || check_error 1 "Invalid PEERING_ID returned"
CREATED_RESOURCES+=("VPC Peering Connection: $PEERING_ID")
@@ -293,7 +312,7 @@ check_error $? "Timeout waiting for peering connection to become active"
# Create a route table for VPC1
echo "Creating route table for VPC1..."
-RTB1_ID=$(log_cmd "aws ec2 create-route-table --region '$AWS_REGION' --vpc-id '$VPC1_ID' --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=VPC1-RouteTable}]' --query 'RouteTable.RouteTableId' --output text")
+RTB1_ID=$(log_cmd "aws ec2 create-route-table --region '$AWS_REGION' --vpc-id '$VPC1_ID' --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=VPC1-RouteTable},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'RouteTable.RouteTableId' --output text")
check_error $? "Failed to create route table for VPC1"
RTB1_ID=$(sanitize_var "$RTB1_ID") || check_error 1 "Invalid RTB1_ID returned"
CREATED_RESOURCES+=("Route Table for VPC1: $RTB1_ID")
@@ -317,7 +336,7 @@ echo "Route table associated with subnet in VPC1"
# Create a route table for VPC2
echo "Creating route table for VPC2..."
-RTB2_ID=$(log_cmd "aws ec2 create-route-table --region '$AWS_REGION' --vpc-id '$VPC2_ID' --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=VPC2-RouteTable}]' --query 'RouteTable.RouteTableId' --output text")
+RTB2_ID=$(log_cmd "aws ec2 create-route-table --region '$AWS_REGION' --vpc-id '$VPC2_ID' --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=VPC2-RouteTable},{Key=project,Value=doc-smith},{Key=tutorial,Value=vpc-peering}]' --query 'RouteTable.RouteTableId' --output text")
check_error $? "Failed to create route table for VPC2"
RTB2_ID=$(sanitize_var "$RTB2_ID") || check_error 1 "Invalid RTB2_ID returned"
CREATED_RESOURCES+=("Route Table for VPC2: $RTB2_ID")
@@ -363,7 +382,7 @@ echo "Route Table 2 ID: $RTB2_ID"
echo "Route Table 2 Association ID: $RTB2_ASSOC_ID"
echo ""
echo "Created resources:"
-for resource in "${CREATED_RESOURCES[@]+"${CREATED_RESOURCES[@]}"}"; do
+for resource in "${CREATED_RESOURCES[@]}"; do
echo "- $resource"
done
echo "=============================================="
diff --git a/tuts/016-opensearch-service-gs/opensearch-service-gs.sh b/tuts/016-opensearch-service-gs/opensearch-service-gs.sh
index bc6e4e2..e75a2a5 100644
--- a/tuts/016-opensearch-service-gs/opensearch-service-gs.sh
+++ b/tuts/016-opensearch-service-gs/opensearch-service-gs.sh
@@ -129,7 +129,7 @@ CREATE_OUTPUT=$(aws opensearch create-domain \
--domain-endpoint-options "EnforceHTTPS=true,TLSSecurityPolicy=Policy-Min-TLS-1-2-2019-07" \
--advanced-security-options "Enabled=true,InternalUserDatabaseEnabled=true,MasterUserOptions={MasterUserName=$MASTER_USER,MasterUserPassword=$MASTER_PASSWORD}" \
--access-policies "$ACCESS_POLICY" \
- --tags "Key=Environment,Value=Tutorial" "Key=Purpose,Value=OpenSearchGettingStarted" 2>&1)
+ --tags "Key=Environment,Value=Tutorial" "Key=Purpose,Value=OpenSearchGettingStarted" "Key=project,Value=doc-smith" "Key=tutorial,Value=opensearch-service-gs" 2>&1)
# Check if domain creation was successful
if [[ $? -ne 0 ]]; then
diff --git a/tuts/018-ecs-ec2/ecs-ec2-getting-started.sh b/tuts/018-ecs-ec2/ecs-ec2-getting-started.sh
index b87f109..f8fea40 100644
--- a/tuts/018-ecs-ec2/ecs-ec2-getting-started.sh
+++ b/tuts/018-ecs-ec2/ecs-ec2-getting-started.sh
@@ -18,6 +18,10 @@ SERVICE_NAME="nginx-service-$(openssl rand -hex 4)"
KEY_PAIR_NAME="ecs-tutorial-key-$(openssl rand -hex 4)"
SECURITY_GROUP_NAME="ecs-tutorial-sg-$(openssl rand -hex 4)"
+# Tags
+PROJECT_TAG="doc-smith"
+TUTORIAL_TAG="ecs-ec2"
+
# Get current AWS region dynamically
AWS_REGION=$(aws configure get region || echo "us-east-1")
@@ -207,7 +211,7 @@ check_prerequisites() {
create_cluster() {
log "Creating ECS cluster: $CLUSTER_NAME"
- CLUSTER_ARN=$(aws ecs create-cluster --cluster-name "$CLUSTER_NAME" --query 'cluster.clusterArn' --output text)
+ CLUSTER_ARN=$(aws ecs create-cluster --cluster-name "$CLUSTER_NAME" --tags key=project,value=$PROJECT_TAG key=tutorial,value=$TUTORIAL_TAG --query 'cluster.clusterArn' --output text)
if [[ -z "$CLUSTER_ARN" ]]; then
log "ERROR: Failed to create cluster"
@@ -230,6 +234,8 @@ create_key_pair() {
log "Created key pair: $KEY_PAIR_NAME"
CREATED_RESOURCES+=("EC2 Key Pair: $KEY_PAIR_NAME")
+
+ aws ec2 create-tags --resources "$KEY_PAIR_NAME" --tags Key=project,Value=$PROJECT_TAG Key=tutorial,Value=$TUTORIAL_TAG 2>>"$LOG_FILE" || log "WARNING: Failed to tag key pair"
}
# Function to create security group
@@ -240,6 +246,7 @@ create_security_group() {
--group-name "$SECURITY_GROUP_NAME" \
--description "ECS tutorial security group" \
--vpc-id "$DEFAULT_VPC" \
+ --tag-specifications "ResourceType=security-group,Tags=[{Key=project,Value=$PROJECT_TAG},{Key=tutorial,Value=$TUTORIAL_TAG}]" \
--query 'GroupId' --output text)
if [[ -z "$SECURITY_GROUP_ID" ]]; then
@@ -312,6 +319,8 @@ EOF
--role-name ecsInstanceRole \
--assume-role-policy-document file://ecs-instance-trust-policy.json
+ aws iam tag-role --role-name ecsInstanceRole --tags Key=project,Value=$PROJECT_TAG Key=tutorial,Value=$TUTORIAL_TAG
+
# Attach managed policy
aws iam attach-role-policy \
--role-name ecsInstanceRole \
@@ -363,7 +372,7 @@ EOF
--subnet-id "$DEFAULT_SUBNET" \
--iam-instance-profile Name=ecsInstanceRole \
--user-data file://ecs-user-data.sh \
- --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=ecs-tutorial-instance}]" \
+ --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=ecs-tutorial-instance},{Key=project,Value=$PROJECT_TAG},{Key=tutorial,Value=$TUTORIAL_TAG}]" \
--monitoring Enabled=false \
--metadata-options HttpTokens=required,HttpPutResponseHopLimit=1 \
--query 'Instances[0].InstanceId' --output text)
@@ -441,13 +450,25 @@ register_task_definition() {
}
],
"requiresCompatibilities": ["EC2"],
- "networkMode": "bridge"
+ "networkMode": "bridge",
+ "tags": [
+ {
+ "key": "project",
+ "value": "PROJECT_TAG_PLACEHOLDER"
+ },
+ {
+ "key": "tutorial",
+ "value": "TUTORIAL_TAG_PLACEHOLDER"
+ }
+ ]
}
EOF
# Replace placeholders securely
sed -i "s|TASK_FAMILY_PLACEHOLDER|$TASK_FAMILY|g" task-definition.json
sed -i "s|REGION_PLACEHOLDER|$AWS_REGION|g" task-definition.json
+ sed -i "s|PROJECT_TAG_PLACEHOLDER|$PROJECT_TAG|g" task-definition.json
+ sed -i "s|TUTORIAL_TAG_PLACEHOLDER|$TUTORIAL_TAG|g" task-definition.json
# FIXED: Validate JSON before registration
if ! jq empty task-definition.json 2>/dev/null; then
@@ -482,6 +503,7 @@ create_service() {
--service-name "$SERVICE_NAME" \
--task-definition "$TASK_FAMILY" \
--desired-count 1 \
+ --tags key=project,value=$PROJECT_TAG key=tutorial,value=$TUTORIAL_TAG \
--query 'service.serviceArn' --output text)
if [[ -z "$SERVICE_ARN" ]]; then
diff --git a/tuts/019-lambda-gettingstarted/lambda-gettingstarted.sh b/tuts/019-lambda-gettingstarted/lambda-gettingstarted.sh
index 2f3aded..bfe118f 100644
--- a/tuts/019-lambda-gettingstarted/lambda-gettingstarted.sh
+++ b/tuts/019-lambda-gettingstarted/lambda-gettingstarted.sh
@@ -265,6 +265,10 @@ ROLE_ARN="$ROLE_OUTPUT"
CREATED_RESOURCES+=("iam-role:${ROLE_NAME}")
echo "Role ARN: ${ROLE_ARN}"
+aws iam tag-role \
+ --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=lambda-gettingstarted
+
echo ""
echo "Attaching AWSLambdaBasicExecutionRole policy..."
aws iam attach-role-policy \
@@ -313,6 +317,7 @@ CREATE_OUTPUT=$(aws lambda create-function \
--handler "$HANDLER" \
--architectures x86_64 \
--zip-file "fileb://${TEMP_DIR}/function.zip" \
+ --tags project=doc-smith,tutorial=lambda-gettingstarted \
--query '[FunctionName, FunctionArn, Runtime, State]' \
--output text 2>&1)
@@ -419,6 +424,10 @@ fi
CREATED_RESOURCES+=("log-group:${LOG_GROUP_NAME}")
+aws logs tag-log-group \
+ --log-group-name "$LOG_GROUP_NAME" \
+ --tags project=doc-smith,tutorial=lambda-gettingstarted
+
###############################################################################
# Summary and cleanup
###############################################################################
diff --git a/tuts/020-ebs-gs-volumes/ebs-gs-volumes.sh b/tuts/020-ebs-gs-volumes/ebs-gs-volumes.sh
old mode 100755
new mode 100644
index 1834c81..b3c5fc7
--- a/tuts/020-ebs-gs-volumes/ebs-gs-volumes.sh
+++ b/tuts/020-ebs-gs-volumes/ebs-gs-volumes.sh
@@ -133,7 +133,7 @@ VOLUME_ID=$(aws ec2 create-volume \
--volume-type gp3 \
--size 10 \
--availability-zone "$AZ" \
- --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=EBSTutorialVolume},{Key=Purpose,Value=Tutorial}]' \
+ --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=EBSTutorialVolume},{Key=Purpose,Value=Tutorial},{Key=project,Value=doc-smith},{Key=tutorial,Value=ebs-gs-volumes}]' \
--query 'VolumeId' \
--output text)
@@ -233,6 +233,7 @@ if [[ "$ATTACH_CHOICE" =~ ^[Yy]$ ]]; then
--group-name "$SG_NAME" \
--description "Security group for EBS tutorial" \
--vpc-id "$DEFAULT_VPC_ID" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=ebs-gs-volumes}]' \
--query "GroupId" \
--output text)
@@ -258,7 +259,7 @@ if [[ "$ATTACH_CHOICE" =~ ^[Yy]$ ]]; then
--instance-type "$INSTANCE_TYPE" \
--subnet-id "$SUBNET_ID" \
--security-group-ids "$SG_ID" \
- --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=EBSTutorialInstance},{Key=Purpose,Value=Tutorial}]' \
+ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=EBSTutorialInstance},{Key=Purpose,Value=Tutorial},{Key=project,Value=doc-smith},{Key=tutorial,Value=ebs-gs-volumes}]' \
--query "Instances[0].InstanceId" \
--output text)
@@ -373,4 +374,4 @@ fi
echo ""
echo "Script completed at $(date)"
-echo "=============================================="
+echo "=============================================="
\ No newline at end of file
diff --git a/tuts/021-cloudformation-gs/cloudformation-gs.sh b/tuts/021-cloudformation-gs/cloudformation-gs.sh
index 9270be9..61989b3 100644
--- a/tuts/021-cloudformation-gs/cloudformation-gs.sh
+++ b/tuts/021-cloudformation-gs/cloudformation-gs.sh
@@ -284,6 +284,7 @@ if ! CREATE_RESULT=$(aws cloudformation create-stack \
ParameterKey=InstanceType,ParameterValue=t2.micro \
ParameterKey=MyIP,ParameterValue="$MY_IP_CIDR" \
--capabilities CAPABILITY_IAM \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudformation-gs \
--region "$AWS_REGION" \
--output text 2>&1); then
handle_error "Stack creation failed: $CREATE_RESULT"
diff --git a/tuts/022-ebs-intermediate/ebs-intermediate.sh b/tuts/022-ebs-intermediate/ebs-intermediate.sh
index 2e7fe62..9efd0ca 100644
--- a/tuts/022-ebs-intermediate/ebs-intermediate.sh
+++ b/tuts/022-ebs-intermediate/ebs-intermediate.sh
@@ -192,7 +192,7 @@ fi
# Step 2: Create a test volume for snapshot with minimal size for cost optimization
echo "Step 2: Creating a test volume (1 GiB for testing)..."
-VOLUME_ID=$(aws ec2 create-volume --region "$AWS_REGION" --availability-zone "$AVAILABILITY_ZONE" --size 1 --volume-type gp3 --iops 3000 --throughput 125 --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=ebs-tutorial-volume},{Key=ManagedBy,Value=ebs-intermediate-script}]' --query 'VolumeId' --output text)
+VOLUME_ID=$(aws ec2 create-volume --region "$AWS_REGION" --availability-zone "$AVAILABILITY_ZONE" --size 1 --volume-type gp3 --iops 3000 --throughput 125 --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=ebs-tutorial-volume},{Key=ManagedBy,Value=ebs-intermediate-script},{Key=project,Value=doc-smith},{Key=tutorial,Value=ebs-intermediate}]' --query 'VolumeId' --output text)
check_status "Creating test volume"
# Security: Validate volume ID
@@ -209,7 +209,7 @@ check_status "Waiting for volume"
# Step 3: Create a snapshot of the volume
echo "Step 3: Creating snapshot of the volume..."
-SNAPSHOT_ID=$(aws ec2 create-snapshot --region "$AWS_REGION" --volume-id "$VOLUME_ID" --description "Snapshot for EBS tutorial - $(date +%Y-%m-%d)" --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=ebs-tutorial-snapshot},{Key=ManagedBy,Value=ebs-intermediate-script}]' --query 'SnapshotId' --output text)
+SNAPSHOT_ID=$(aws ec2 create-snapshot --region "$AWS_REGION" --volume-id "$VOLUME_ID" --description "Snapshot for EBS tutorial - $(date +%Y-%m-%d)" --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=ebs-tutorial-snapshot},{Key=ManagedBy,Value=ebs-intermediate-script},{Key=project,Value=doc-smith},{Key=tutorial,Value=ebs-intermediate}]' --query 'SnapshotId' --output text)
check_status "Creating snapshot"
# Security: Validate snapshot ID
@@ -227,7 +227,7 @@ echo "Snapshot completed."
# Step 4: Create a new volume from the snapshot
echo "Step 4: Creating a new volume from the snapshot..."
-NEW_VOLUME_ID=$(aws ec2 create-volume --region "$AWS_REGION" --snapshot-id "$SNAPSHOT_ID" --availability-zone "$AVAILABILITY_ZONE" --volume-type gp3 --iops 3000 --throughput 125 --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=ebs-tutorial-volume-from-snapshot},{Key=ManagedBy,Value=ebs-intermediate-script}]' --query 'VolumeId' --output text)
+NEW_VOLUME_ID=$(aws ec2 create-volume --region "$AWS_REGION" --snapshot-id "$SNAPSHOT_ID" --availability-zone "$AVAILABILITY_ZONE" --volume-type gp3 --iops 3000 --throughput 125 --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=ebs-tutorial-volume-from-snapshot},{Key=ManagedBy,Value=ebs-intermediate-script},{Key=project,Value=doc-smith},{Key=tutorial,Value=ebs-intermediate}]' --query 'VolumeId' --output text)
check_status "Creating new volume from snapshot"
# Security: Validate new volume ID
diff --git a/tuts/024-glue-gs/glue-gs.sh b/tuts/024-glue-gs/glue-gs.sh
index 4e660bf..eb523c3 100644
--- a/tuts/024-glue-gs/glue-gs.sh
+++ b/tuts/024-glue-gs/glue-gs.sh
@@ -137,6 +137,13 @@ create_database() {
exit 1
fi
+ ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
+ aws glue tag-resource \
+ --resource-arn "arn:aws:glue:${AWS_REGION}:${ACCOUNT_ID}:database/${DB_NAME}" \
+ --tags-to-add Key=project,Value=doc-smith Key=tutorial,Value=glue-gs \
+ --region "$AWS_REGION" \
+ 2>/dev/null || true
+
DATABASE_CREATED=true
CREATED_RESOURCES+=("database:$DB_NAME")
echo "Database $DB_NAME created successfully."
@@ -223,6 +230,7 @@ create_table() {
prepare_table_input
+ local TABLE_ARN
if ! aws glue create-table \
--database-name "$DB_NAME" \
--table-input "file://${TABLE_INPUT_FILE}" \
@@ -233,6 +241,12 @@ create_table() {
exit 1
fi
+ aws glue tag-resource \
+ --resource-arn "arn:aws:glue:${AWS_REGION}:${ACCOUNT_ID}:table/${DB_NAME}/${TABLE_NAME}" \
+ --tags-to-add Key=project,Value=doc-smith Key=tutorial,Value=glue-gs \
+ --region "$AWS_REGION" \
+ 2>/dev/null || true
+
CREATED_RESOURCES+=("table:$TABLE_NAME")
echo "Table $TABLE_NAME created successfully."
}
diff --git a/tuts/025-documentdb-gs/documentdb-gs.sh b/tuts/025-documentdb-gs/documentdb-gs.sh
index d98a616..48d0524 100644
--- a/tuts/025-documentdb-gs/documentdb-gs.sh
+++ b/tuts/025-documentdb-gs/documentdb-gs.sh
@@ -233,6 +233,7 @@ SECRET_OUTPUT=$(aws secretsmanager create-secret \
--name "$SECRET_NAME" \
--description "DocumentDB master password for ${CLUSTER_ID}" \
--secret-string file://"$TEMP_PASS_FILE" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=documentdb-gs \
--output text --query "ARN" 2>&1)
# Securely clear password from memory
@@ -322,6 +323,7 @@ SUBNET_GROUP_OUTPUT=$(aws docdb create-db-subnet-group \
--db-subnet-group-name "$SUBNET_GROUP_NAME" \
--db-subnet-group-description "Subnet group for DocumentDB getting started" \
--subnet-ids $SUBNET_IDS \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=documentdb-gs \
--query "DBSubnetGroup.DBSubnetGroupName" --output text 2>&1)
if echo "$SUBNET_GROUP_OUTPUT" | grep -iq "error"; then
@@ -355,6 +357,7 @@ CLUSTER_OUTPUT=$(aws docdb create-db-cluster \
--kms-key-id "alias/aws/docdb" \
--no-deletion-protection \
--enable-cloudwatch-logs-exports '["audit","error","general","slowquery"]' \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=documentdb-gs \
--query "DBCluster.DBClusterIdentifier" --output text 2>&1)
# Clear password immediately after use
@@ -385,6 +388,7 @@ INSTANCE_OUTPUT=$(aws docdb create-db-instance \
--db-instance-class "$INSTANCE_CLASS" \
--db-cluster-identifier "$CLUSTER_ID" \
--engine docdb \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=documentdb-gs \
--query "DBInstance.DBInstanceIdentifier" --output text 2>&1)
if echo "$INSTANCE_OUTPUT" | grep -iq "error"; then
diff --git a/tuts/027-connect-gs/connect-gs.sh b/tuts/027-connect-gs/connect-gs.sh
index 3f29b18..9dd0b15 100644
--- a/tuts/027-connect-gs/connect-gs.sh
+++ b/tuts/027-connect-gs/connect-gs.sh
@@ -176,6 +176,11 @@ fi
echo "Successfully created Amazon Connect instance with ID: $INSTANCE_ID" | tee -a "$LOG_FILE"
echo "Instance ARN: $INSTANCE_ARN" | tee -a "$LOG_FILE"
+# Tag the instance
+aws connect tag-resource --resource-arn "$INSTANCE_ARN" \
+ --tags project=doc-smith,tutorial=connect-gs \
+ --region "$AWS_REGION"
+
# Wait for the instance to be fully created and active
if ! wait_for_instance "$INSTANCE_ID"; then
echo "ERROR: Instance did not become fully active within the timeout period" | tee -a "$LOG_FILE"
diff --git a/tuts/028-sagemaker-featurestore/sagemaker-featurestore.sh b/tuts/028-sagemaker-featurestore/sagemaker-featurestore.sh
old mode 100755
new mode 100644
index 95bee00..5edf892
--- a/tuts/028-sagemaker-featurestore/sagemaker-featurestore.sh
+++ b/tuts/028-sagemaker-featurestore/sagemaker-featurestore.sh
@@ -121,6 +121,10 @@ create_sagemaker_role() {
echo "Role created successfully" >&2
CREATED_RESOURCES+=("IAMRole:$role_name")
+ # Tag the role
+ echo "Tagging IAM role..." >&2
+ aws iam tag-role --role-name "$role_name" --tags Key=project,Value=doc-smith Key=tutorial,Value=sagemaker-featurestore 2>&1
+
# Attach necessary policies
echo "Attaching policies to role..." >&2
@@ -235,6 +239,10 @@ fi
echo "$BUCKET_RESULT"
CREATED_RESOURCES+=("S3Bucket:$S3_BUCKET_NAME")
+# Tag the S3 bucket
+echo "Tagging S3 bucket: $S3_BUCKET_NAME"
+aws s3api put-bucket-tagging --bucket "$S3_BUCKET_NAME" --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=sagemaker-featurestore}]' 2>&1
+
# Block public access to the bucket
BLOCK_RESULT=$(aws s3api put-public-access-block \
--bucket "$S3_BUCKET_NAME" \
@@ -275,7 +283,8 @@ CUSTOMERS_RESPONSE=$(aws sagemaker create-feature-group \
},
"DisableGlueTableCreation": false
}' \
- --role-arn "$ROLE_ARN" 2>&1)
+ --role-arn "$ROLE_ARN" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=sagemaker-featurestore 2>&1)
if echo "$CUSTOMERS_RESPONSE" | grep -i "error" > /dev/null; then
echo "Failed to create customers feature group: $CUSTOMERS_RESPONSE"
@@ -310,7 +319,8 @@ ORDERS_RESPONSE=$(aws sagemaker create-feature-group \
},
"DisableGlueTableCreation": false
}' \
- --role-arn "$ROLE_ARN" 2>&1)
+ --role-arn "$ROLE_ARN" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=sagemaker-featurestore 2>&1)
if echo "$ORDERS_RESPONSE" | grep -i "error" > /dev/null; then
echo "Failed to create orders feature group: $ORDERS_RESPONSE"
@@ -513,4 +523,4 @@ else
fi
fi
-echo "Script completed at $(date)"
+echo "Script completed at $(date)"
\ No newline at end of file
diff --git a/tuts/030-marketplace-buyer-gs/marketplace-buyer-getting-started.sh b/tuts/030-marketplace-buyer-gs/marketplace-buyer-getting-started.sh
index a03456d..d08dcbe 100644
--- a/tuts/030-marketplace-buyer-gs/marketplace-buyer-getting-started.sh
+++ b/tuts/030-marketplace-buyer-gs/marketplace-buyer-getting-started.sh
@@ -256,6 +256,7 @@ INSTANCE_OUTPUT=$(aws ec2 run-instances \
--count 1 \
--region "$AWS_REGION" \
--monitoring Enabled=false \
+ --tag-specifications 'ResourceType=instance,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=marketplace-buyer-gs}]' \
--output json) || {
echo "ERROR: Failed to launch instance" >&2
exit 1
diff --git a/tuts/031-cloudwatch-dynamicdash/cloudwatch-dynamicdash.sh b/tuts/031-cloudwatch-dynamicdash/cloudwatch-dynamicdash.sh
index 52e3aaf..4006533 100644
--- a/tuts/031-cloudwatch-dynamicdash/cloudwatch-dynamicdash.sh
+++ b/tuts/031-cloudwatch-dynamicdash/cloudwatch-dynamicdash.sh
@@ -11,7 +11,7 @@ exec > >(tee -a "$LOG_FILE") 2>&1
echo "$(date): Starting CloudWatch dashboard creation script"
# Security: Set strict error handling
-set -euo pipefail
+set -uo pipefail
trap 'handle_error "Script failed at line $LINENO"' ERR
# Function to handle errors
@@ -102,6 +102,7 @@ EOF
if ! ROLE_ARN=$(aws iam create-role \
--role-name "$ROLE_NAME" \
--assume-role-policy-document "$TRUST_POLICY" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudwatch-dynamicdash \
--query "Role.Arn" \
--output text 2>/dev/null); then
handle_error "Failed to create IAM role for Lambda function"
@@ -126,6 +127,7 @@ EOF
--role "$ROLE_ARN" \
--handler index.handler \
--zip-file fileb://function.zip \
+ --tags project=doc-smith,tutorial=cloudwatch-dynamicdash \
--region "$REGION" > /dev/null 2>&1; then
aws iam detach-role-policy \
--role-name "$ROLE_NAME" \
@@ -247,8 +249,9 @@ if ! jq empty "$DASHBOARD_JSON" 2>/dev/null; then
fi
# Create the dashboard using the JSON file
+DASHBOARD_NAME="LambdaMetricsDashboard-$(date +%s)"
if ! DASHBOARD_RESULT=$(aws cloudwatch put-dashboard \
- --dashboard-name "LambdaMetricsDashboard-$(date +%s)" \
+ --dashboard-name "$DASHBOARD_NAME" \
--dashboard-body file://"$DASHBOARD_JSON" \
--region "$REGION" 2>&1); then
# If we created resources, clean them up
@@ -271,9 +274,6 @@ else
echo "Dashboard created successfully!"
fi
-# Extract dashboard name from result
-DASHBOARD_NAME=$(echo "$DASHBOARD_RESULT" | grep -oP '"DashboardName"\s*:\s*"\K[^"]+' || echo "LambdaMetricsDashboard")
-
# Verify the dashboard was created
echo "Verifying dashboard creation..."
if ! DASHBOARD_INFO=$(aws cloudwatch get-dashboard --dashboard-name "$DASHBOARD_NAME" --region "$REGION" 2>&1); then
diff --git a/tuts/032-cloudwatch-streams/cloudwatch-streams.sh b/tuts/032-cloudwatch-streams/cloudwatch-streams.sh
index 14cf071..4a4e171 100644
--- a/tuts/032-cloudwatch-streams/cloudwatch-streams.sh
+++ b/tuts/032-cloudwatch-streams/cloudwatch-streams.sh
@@ -156,7 +156,7 @@ if ! python3 -m json.tool trust-policy.json > /dev/null 2>&1; then
exit 1
fi
-ROLE_OUTPUT=$(log_cmd "aws iam create-role --role-name '$ROLE_NAME' --assume-role-policy-document file://trust-policy.json --output json")
+ROLE_OUTPUT=$(log_cmd "aws iam create-role --role-name '$ROLE_NAME' --assume-role-policy-document file://trust-policy.json --tags Key=project,Value=doc-smith Key=tutorial,Value=cloudwatch-streams --output json")
check_error "$ROLE_OUTPUT" $? "Failed to create IAM role"
ROLE_ARN=$(echo "$ROLE_OUTPUT" | python3 -c "import sys, json; print(json.load(sys.stdin)['Role']['Arn'])" 2>/dev/null)
@@ -210,12 +210,12 @@ fi
# Create first Lambda function
echo "Creating first Lambda function: $LAMBDA_FUNCTION1..." | tee -a "$LOG_FILE"
-LAMBDA1_OUTPUT=$(log_cmd "aws lambda create-function --function-name '$LAMBDA_FUNCTION1' --runtime python3.11 --role '$ROLE_ARN' --handler lambda_function.handler --zip-file fileb://lambda_function.zip --timeout 30 --memory-size 128")
+LAMBDA1_OUTPUT=$(log_cmd "aws lambda create-function --function-name '$LAMBDA_FUNCTION1' --runtime python3.11 --role '$ROLE_ARN' --handler lambda_function.handler --zip-file fileb://lambda_function.zip --timeout 30 --memory-size 128 --tags project=doc-smith,tutorial=cloudwatch-streams")
check_error "$LAMBDA1_OUTPUT" $? "Failed to create first Lambda function"
# Create second Lambda function
echo "Creating second Lambda function: $LAMBDA_FUNCTION2..." | tee -a "$LOG_FILE"
-LAMBDA2_OUTPUT=$(log_cmd "aws lambda create-function --function-name '$LAMBDA_FUNCTION2' --runtime python3.11 --role '$ROLE_ARN' --handler lambda_function.handler --zip-file fileb://lambda_function.zip --timeout 30 --memory-size 128")
+LAMBDA2_OUTPUT=$(log_cmd "aws lambda create-function --function-name '$LAMBDA_FUNCTION2' --runtime python3.11 --role '$ROLE_ARN' --handler lambda_function.handler --zip-file fileb://lambda_function.zip --timeout 30 --memory-size 128 --tags project=doc-smith,tutorial=cloudwatch-streams")
check_error "$LAMBDA2_OUTPUT" $? "Failed to create second Lambda function"
# Invoke Lambda functions to generate some metrics
diff --git a/tuts/034-eks-gs/eks-gs.sh b/tuts/034-eks-gs/eks-gs.sh
index d55964c..97b0275 100755
--- a/tuts/034-eks-gs/eks-gs.sh
+++ b/tuts/034-eks-gs/eks-gs.sh
@@ -153,7 +153,8 @@ echo "Creating CloudFormation stack: $STACK_NAME"
# Create the CloudFormation stack
CF_CREATE_OUTPUT=$(aws cloudformation create-stack \
--stack-name "$STACK_NAME" \
- --template-url https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/amazon-eks-vpc-private-subnets.yaml)
+ --template-url https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/amazon-eks-vpc-private-subnets.yaml \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=eks-gs)
check_command "$CF_CREATE_OUTPUT"
CREATED_RESOURCES+=("CloudFormation Stack: $STACK_NAME")
@@ -190,6 +191,8 @@ CLUSTER_ROLE_OUTPUT=$(aws iam create-role \
--role-name "$CLUSTER_ROLE_NAME" \
--assume-role-policy-document file://"eks-cluster-role-trust-policy.json")
check_command "$CLUSTER_ROLE_OUTPUT"
+aws iam tag-role --role-name "$CLUSTER_ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=eks-gs
CREATED_RESOURCES+=("IAM Role: $CLUSTER_ROLE_NAME")
# Attach policy to cluster role
@@ -222,6 +225,8 @@ NODE_ROLE_OUTPUT=$(aws iam create-role \
--role-name "$NODE_ROLE_NAME" \
--assume-role-policy-document file://"node-role-trust-policy.json")
check_command "$NODE_ROLE_OUTPUT"
+aws iam tag-role --role-name "$NODE_ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=eks-gs
CREATED_RESOURCES+=("IAM Role: $NODE_ROLE_NAME")
# Attach policies to node role
@@ -283,7 +288,8 @@ echo "Creating EKS cluster (this will take 10-15 minutes)..."
CREATE_CLUSTER_OUTPUT=$(aws eks create-cluster \
--name "$CLUSTER_NAME" \
--role-arn "$CLUSTER_ROLE_ARN" \
- --resources-vpc-config subnetIds="$SUBNET_IDS",securityGroupIds="$SECURITY_GROUP_ID")
+ --resources-vpc-config subnetIds="$SUBNET_IDS",securityGroupIds="$SECURITY_GROUP_ID" \
+ --tags Key=project,Value=doc-smith,Key=tutorial,Value=eks-gs)
check_command "$CREATE_CLUSTER_OUTPUT"
CREATED_RESOURCES+=("EKS Cluster: $CLUSTER_NAME")
@@ -335,7 +341,8 @@ CREATE_NODEGROUP_OUTPUT=$(aws eks create-nodegroup \
--cluster-name "$CLUSTER_NAME" \
--nodegroup-name "$NODEGROUP_NAME" \
--node-role "$NODE_ROLE_ARN" \
- --subnets "${SUBNET_IDS_ARRAY[@]}")
+ --subnets "${SUBNET_IDS_ARRAY[@]}" \
+ --tags Key=project,Value=doc-smith,Key=tutorial,Value=eks-gs)
check_command "$CREATE_NODEGROUP_OUTPUT"
CREATED_RESOURCES+=("EKS Node Group: $NODEGROUP_NAME")
diff --git a/tuts/035-workspaces-personal/workspaces-personal.sh b/tuts/035-workspaces-personal/workspaces-personal.sh
index a23c3ce..f346b5e 100755
--- a/tuts/035-workspaces-personal/workspaces-personal.sh
+++ b/tuts/035-workspaces-personal/workspaces-personal.sh
@@ -309,9 +309,9 @@ WORKSPACE_JSON="{\"DirectoryId\":\"$DIRECTORY_ID\",\"UserName\":\"$USERNAME\",\"
# Add tags if specified
if [ -n "$TAGS_JSON" ]; then
USER_TAGS=$(echo "$TAGS_JSON" | sed 's/^\[//;s/\]$//')
- WORKSPACE_JSON="$WORKSPACE_JSON,\"Tags\":[$USER_TAGS,{\"Key\":\"project\",\"Value\":\"doc-smith\"},{\"Key\":\"tutorial\",\"Value\":\"035-workspaces-personal\"}]"
+ WORKSPACE_JSON="$WORKSPACE_JSON,\"Tags\":[$USER_TAGS,{\"Key\":\"project\",\"Value\":\"doc-smith\"},{\"Key\":\"tutorial\",\"Value\":\"workspaces-personal\"}]"
else
- WORKSPACE_JSON="$WORKSPACE_JSON,\"Tags\":[{\"Key\":\"project\",\"Value\":\"doc-smith\"},{\"Key\":\"tutorial\",\"Value\":\"035-workspaces-personal\"}]"
+ WORKSPACE_JSON="$WORKSPACE_JSON,\"Tags\":[{\"Key\":\"project\",\"Value\":\"doc-smith\"},{\"Key\":\"tutorial\",\"Value\":\"workspaces-personal\"}]"
fi
# Close the JSON object
diff --git a/tuts/036-rds-gs/rds-gs.sh b/tuts/036-rds-gs/rds-gs.sh
old mode 100755
new mode 100644
index f294ef7..5bf2f6e
--- a/tuts/036-rds-gs/rds-gs.sh
+++ b/tuts/036-rds-gs/rds-gs.sh
@@ -93,7 +93,8 @@ echo "Step 3: Creating security group for RDS..."
SG_OUTPUT=$(aws ec2 create-security-group \
--group-name "$SECURITY_GROUP_NAME" \
--description "Security group for RDS database access" \
- --vpc-id "$VPC_ID")
+ --vpc-id "$VPC_ID" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=rds-gs}]')
check_error "$SG_OUTPUT" "aws ec2 create-security-group"
SECURITY_GROUP_ID=$(echo "$SG_OUTPUT" | grep -o '"GroupId": "[^"]*' | cut -d'"' -f4)
@@ -125,7 +126,8 @@ SUBNET2=${SUBNET_IDS[1]}
SUBNET_GROUP_OUTPUT=$(aws rds create-db-subnet-group \
--db-subnet-group-name "$DB_SUBNET_GROUP_NAME" \
--db-subnet-group-description "Subnet group for RDS tutorial" \
- --subnet-ids "$SUBNET1" "$SUBNET2")
+ --subnet-ids "$SUBNET1" "$SUBNET2" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=rds-gs)
check_error "$SUBNET_GROUP_OUTPUT" "aws rds create-db-subnet-group"
CREATED_SUBNET_GROUP="true"
@@ -138,7 +140,8 @@ SECRET_NAME="rds-db-credentials-${RANDOM_ID}"
SECRET_OUTPUT=$(aws secretsmanager create-secret \
--name "$SECRET_NAME" \
--description "RDS DB credentials for $DB_INSTANCE_ID" \
- --secret-string '{"username":"adminuser","password":"'"$(openssl rand -base64 16)"'"}')
+ --secret-string '{"username":"adminuser","password":"'"$(openssl rand -base64 16)"'"}' \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=rds-gs)
check_error "$SECRET_OUTPUT" "aws secretsmanager create-secret"
SECRET_ARN=$(echo "$SECRET_OUTPUT" | grep -o '"ARN": "[^"]*' | cut -d'"' -f4)
@@ -169,7 +172,8 @@ DB_OUTPUT=$(aws rds create-db-instance \
--db-subnet-group-name "$DB_SUBNET_GROUP_NAME" \
--backup-retention-period 7 \
--no-publicly-accessible \
- --no-multi-az)
+ --no-multi-az \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=rds-gs)
check_error "$DB_OUTPUT" "aws rds create-db-instance"
CREATED_RESOURCES+=("DB Instance: $DB_INSTANCE_ID")
@@ -251,4 +255,4 @@ else
echo "To clean up later, you'll need to delete these resources manually."
fi
-echo "Script completed successfully!"
+echo "Script completed successfully!"
\ No newline at end of file
diff --git a/tuts/037-emr-gs/emr-gs.sh b/tuts/037-emr-gs/emr-gs.sh
index 313b87b..9232184 100644
--- a/tuts/037-emr-gs/emr-gs.sh
+++ b/tuts/037-emr-gs/emr-gs.sh
@@ -96,6 +96,10 @@ echo "Using bucket name: $BUCKET_NAME"
echo "Creating S3 bucket: $BUCKET_NAME"
aws s3 mb "s3://$BUCKET_NAME" --region "${AWS_REGION:-us-east-1}" || handle_error "Failed to create S3 bucket"
+# Tag the bucket
+aws s3api put-bucket-tagging --bucket "$BUCKET_NAME" \
+ --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=emr-gs}]'
+
# Enable bucket versioning for safety
aws s3api put-bucket-versioning --bucket "$BUCKET_NAME" --versioning-configuration Status=Enabled || true
@@ -204,7 +208,9 @@ if [ -z "$KEY_PAIRS" ]; then
echo "No EC2 key pairs found. Creating a new key pair..."
KEY_NAME="emr-tutorial-key-${RANDOM_ID}"
KEY_NAME_FILE="${KEY_NAME}.pem"
- aws ec2 create-key-pair --key-name "$KEY_NAME" --query "KeyMaterial" --output text > "$KEY_NAME_FILE"
+ aws ec2 create-key-pair --key-name "$KEY_NAME" \
+ --tag-specifications 'ResourceType=key-pair,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=emr-gs}]' \
+ --query "KeyMaterial" --output text > "$KEY_NAME_FILE"
chmod 400 "$KEY_NAME_FILE"
echo "Created new key pair: $KEY_NAME"
else
@@ -225,6 +231,7 @@ CLUSTER_RESPONSE=$(aws emr create-cluster \
--use-default-roles \
--log-uri "s3://$BUCKET_NAME/logs/" \
--ebs-root-volume-size 100 \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=emr-gs \
--security-configuration "EMR-Tutorial-SecurityConfig" 2>/dev/null || true)
# Check for errors in the response
diff --git a/tuts/038-redshift-serverless/redshift-serverless.sh b/tuts/038-redshift-serverless/redshift-serverless.sh
index 93651d3..d007a8f 100755
--- a/tuts/038-redshift-serverless/redshift-serverless.sh
+++ b/tuts/038-redshift-serverless/redshift-serverless.sh
@@ -85,7 +85,8 @@ create_secret() {
local secret_output=$(aws secretsmanager create-secret \
--name "$secret_name" \
--description "$description" \
- --secret-string "{\"username\":\"$username\",\"password\":\"$password\"}" 2>&1)
+ --secret-string "{\"username\":\"$username\",\"password\":\"$password\"}" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=redshift-serverless 2>&1)
if echo "$secret_output" | grep -i "error\|exception\|fail" > /dev/null; then
echo "ERROR: Failed to create secret: $secret_output"
@@ -304,6 +305,8 @@ echo "Creating IAM role $ROLE_NAME..."
ROLE_OUTPUT=$(aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document file://redshift-trust-policy.json 2>&1)
echo "$ROLE_OUTPUT"
check_error "$ROLE_OUTPUT" "aws iam create-role"
+aws iam tag-role --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=redshift-serverless
CREATED_RESOURCES+=("IAM Role: $ROLE_NAME")
# Attach S3 policy to the role
@@ -322,7 +325,8 @@ NAMESPACE_OUTPUT=$(aws redshift-serverless create-namespace \
--namespace-name "$NAMESPACE_NAME" \
--admin-username "$ADMIN_USERNAME" \
--admin-user-password "$ADMIN_PASSWORD" \
- --db-name "$DB_NAME" 2>&1)
+ --db-name "$DB_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=redshift-serverless 2>&1)
echo "$NAMESPACE_OUTPUT"
check_error "$NAMESPACE_OUTPUT" "aws redshift-serverless create-namespace"
CREATED_RESOURCES+=("Redshift Serverless Namespace: $NAMESPACE_NAME")
@@ -343,7 +347,8 @@ echo "Creating Redshift Serverless workgroup $WORKGROUP_NAME..."
WORKGROUP_OUTPUT=$(aws redshift-serverless create-workgroup \
--workgroup-name "$WORKGROUP_NAME" \
--namespace-name "$NAMESPACE_NAME" \
- --base-capacity 8 2>&1)
+ --base-capacity 8 \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=redshift-serverless 2>&1)
echo "$WORKGROUP_OUTPUT"
check_error "$WORKGROUP_OUTPUT" "aws redshift-serverless create-workgroup"
CREATED_RESOURCES+=("Redshift Serverless Workgroup: $WORKGROUP_NAME")
diff --git a/tuts/039-redshift-provisioned/redshift-provisioned.sh b/tuts/039-redshift-provisioned/redshift-provisioned.sh
index 73173a6..ce3d283 100644
--- a/tuts/039-redshift-provisioned/redshift-provisioned.sh
+++ b/tuts/039-redshift-provisioned/redshift-provisioned.sh
@@ -163,6 +163,7 @@ CLUSTER_RESULT=$(aws redshift create-cluster \
--db-name "$DB_NAME" \
--port 5439 \
--encrypted \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=redshift-provisioned \
2>&1) || handle_error "Failed to create Redshift cluster"
echo "$CLUSTER_RESULT"
@@ -212,6 +213,10 @@ echo "$ROLE_RESULT"
ROLE_ARN=$(aws iam get-role --role-name "$ROLE_NAME" --query 'Role.Arn' --output text)
echo "Role ARN: $ROLE_ARN"
+# Tag the IAM role
+echo "Tagging IAM role: $ROLE_NAME"
+aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=redshift-provisioned
+
# Create policy document for S3 access with principle of least privilege
echo "Creating S3 access policy"
cat > redshift-s3-policy.json << 'EOF'
diff --git a/tuts/040-qbusiness-ica/qbusiness-ica.sh b/tuts/040-qbusiness-ica/qbusiness-ica.sh
index 7c89b41..77d4b00 100755
--- a/tuts/040-qbusiness-ica/qbusiness-ica.sh
+++ b/tuts/040-qbusiness-ica/qbusiness-ica.sh
@@ -246,6 +246,8 @@ echo "Creating IAM role: $ROLE_NAME" | tee -a "$LOG_FILE"
ROLE_RESULT=$(log_cmd "aws iam create-role --role-name \"$ROLE_NAME\" --assume-role-policy-document file://qbusiness-trust-policy.json --query 'Role.Arn' --output text")
check_error $?
ROLE_ARN="$ROLE_RESULT"
+aws iam tag-role --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=qbusiness-ica
CREATED_RESOURCES+=("IAM Role: $ROLE_ARN")
# Create and attach the policy to the role
@@ -316,6 +318,7 @@ APP_RESULT=$(log_cmd "aws qbusiness create-application --region $AWS_REGION \
--role-arn \"$ROLE_ARN\" \
--description \"Amazon Q Business application created via script\" \
--attachments-configuration '{\"attachmentsControlMode\":\"ENABLED\"}' \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=qbusiness-ica \
--query 'applicationId' --output text")
check_error $?
APP_ID="$APP_RESULT"
diff --git a/tuts/042-qbusiness-anon/qbusiness-anon.sh b/tuts/042-qbusiness-anon/qbusiness-anon.sh
index 55b4ecd..434c2b7 100644
--- a/tuts/042-qbusiness-anon/qbusiness-anon.sh
+++ b/tuts/042-qbusiness-anon/qbusiness-anon.sh
@@ -122,6 +122,8 @@ chmod 600 "$TRUST_POLICY_FILE"
ROLE_NAME="QBusinessServiceRole-${RANDOM_ID}"
ROLE_OUTPUT=$(aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document "file://$TRUST_POLICY_FILE" --output json 2>&1)
check_error "$ROLE_OUTPUT" $? "Failed to create IAM role"
+aws iam tag-role --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=qbusiness-anon
# Extract role ARN using jq for safer JSON parsing
if command -v jq &> /dev/null; then
@@ -153,6 +155,7 @@ APP_OUTPUT=$(aws qbusiness create-application \
--identity-type ANONYMOUS \
--role-arn "$ROLE_ARN" \
--description "Amazon Q Business application with anonymous access" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=qbusiness-anon \
--output json 2>&1)
check_error "$APP_OUTPUT" $? "Failed to create Amazon Q Business application"
diff --git a/tuts/043-amazon-mq-gs/amazon-mq-gs.sh b/tuts/043-amazon-mq-gs/amazon-mq-gs.sh
index 1d13736..680cc34 100644
--- a/tuts/043-amazon-mq-gs/amazon-mq-gs.sh
+++ b/tuts/043-amazon-mq-gs/amazon-mq-gs.sh
@@ -111,7 +111,8 @@ fi
SECRET_RESULT=$(aws secretsmanager create-secret \
--name "$SECRET_NAME" \
--description "Amazon MQ broker credentials for $BROKER_NAME" \
- --secret-string "$CREDENTIALS_JSON" 2>&1)
+ --secret-string "$CREDENTIALS_JSON" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-mq-gs 2>&1)
# Check for errors
if echo "$SECRET_RESULT" | grep -i "error" > /dev/null; then
@@ -142,6 +143,7 @@ BROKER_RESULT=$(aws mq create-broker \
--publicly-accessible \
--auto-minor-version-upgrade \
--storage-type EFS \
+ --tags project=doc-smith,tutorial=amazon-mq-gs \
2>&1)
# Check for errors
diff --git a/tuts/044-amazon-managed-grafana-gs/amazon-managed-grafana-gs.sh b/tuts/044-amazon-managed-grafana-gs/amazon-managed-grafana-gs.sh
index 53fa704..d3bf238 100755
--- a/tuts/044-amazon-managed-grafana-gs/amazon-managed-grafana-gs.sh
+++ b/tuts/044-amazon-managed-grafana-gs/amazon-managed-grafana-gs.sh
@@ -93,6 +93,8 @@ ROLE_OUTPUT=$(aws iam create-role \
--description "Role for Amazon Managed Grafana workspace")
check_error "$ROLE_OUTPUT" "create-role"
+aws iam tag-role --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-managed-grafana-gs
echo "IAM role created successfully"
# Extract role ARN
@@ -149,7 +151,7 @@ WORKSPACE_OUTPUT=$(aws grafana create-workspace \
--workspace-role-arn "$ROLE_ARN" \
--workspace-data-sources "CLOUDWATCH" "PROMETHEUS" "XRAY" \
--grafana-version "10.4" \
- --tags Environment=Development)
+ --tags Environment=Development,project=doc-smith,tutorial=amazon-managed-grafana-gs)
check_error "$WORKSPACE_OUTPUT" "create-workspace"
diff --git a/tuts/045-aws-iam-identity-center-gs/aws-iam-identity-center-gs.sh b/tuts/045-aws-iam-identity-center-gs/aws-iam-identity-center-gs.sh
index 65d152e..3cabfef 100755
--- a/tuts/045-aws-iam-identity-center-gs/aws-iam-identity-center-gs.sh
+++ b/tuts/045-aws-iam-identity-center-gs/aws-iam-identity-center-gs.sh
@@ -274,7 +274,7 @@ else
echo "Creating a new IAM Identity Center instance..." | tee -a "$LOG_FILE"
# Create IAM Identity Center instance (only works for non-organization management accounts)
- INSTANCE_OUTPUT=$(log_cmd "aws sso-admin create-instance --name \"MyIdentityCenter\" --tags Key=Purpose,Value=Tutorial")
+ INSTANCE_OUTPUT=$(log_cmd "aws sso-admin create-instance --name \"MyIdentityCenter\" --tags Key=Purpose,Value=Tutorial Key=project,Value=doc-smith Key=tutorial,Value=aws-iam-identity-center-gs")
check_error "$INSTANCE_OUTPUT" $? "Failed to create IAM Identity Center instance"
# Wait for instance to be created and get instance ARN
@@ -402,6 +402,9 @@ if [[ "$IS_ORGANIZATION_INSTANCE" == "true" ]]; then
cleanup_resources
exit 1
fi
+ aws sso-admin tag-resource --instance-arn "$INSTANCE_ARN" \
+ --resource-arn "$PERMISSION_SET_ARN" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iam-identity-center-gs
track_resource "permission_set" "$INSTANCE_ARN,$PERMISSION_SET_ARN"
echo "Permission set created successfully with ARN: $PERMISSION_SET_ARN" | tee -a "$LOG_FILE"
diff --git a/tuts/046-aws-systems-manager-gs/aws-systems-manager-gs.sh b/tuts/046-aws-systems-manager-gs/aws-systems-manager-gs.sh
index 3fac178..409ade3 100755
--- a/tuts/046-aws-systems-manager-gs/aws-systems-manager-gs.sh
+++ b/tuts/046-aws-systems-manager-gs/aws-systems-manager-gs.sh
@@ -383,6 +383,8 @@ fi
# Track the created policy
track_resource "IAM_POLICY" "$POLICY_ARN"
+aws iam tag-policy --policy-arn "$POLICY_ARN" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-systems-manager-gs
echo "Created policy: $POLICY_ARN" | tee -a "$LOG_FILE"
@@ -450,6 +452,8 @@ fi
# Track the created role
track_resource "IAM_ROLE" "$ROLE_NAME"
+aws iam tag-role --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-systems-manager-gs
echo "Created IAM role: $ROLE_NAME" | tee -a "$LOG_FILE"
echo "Role ARN: $ROLE_ARN" | tee -a "$LOG_FILE"
diff --git a/tuts/047-aws-network-firewall-gs/aws-network-firewall-gs.sh b/tuts/047-aws-network-firewall-gs/aws-network-firewall-gs.sh
index f9957ce..8298703 100755
--- a/tuts/047-aws-network-firewall-gs/aws-network-firewall-gs.sh
+++ b/tuts/047-aws-network-firewall-gs/aws-network-firewall-gs.sh
@@ -447,6 +447,7 @@ STATELESS_RULE_GROUP_ARN=$(aws network-firewall create-rule-group \
--capacity 10 \
--rule-group '{"RulesSource": {"StatelessRulesAndCustomActions": {"StatelessRules": [{"RuleDefinition": {"MatchAttributes": {"Sources": [{"AddressDefinition": "192.0.2.0/24"}], "Destinations": [], "SourcePorts": [], "DestinationPorts": [], "Protocols": []}, "Actions": ["aws:drop"]}, "Priority": 10}]}}}' \
--description "Stateless rule group example" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-network-firewall-gs \
--query 'RuleGroupResponse.RuleGroupArn' \
--output text)
@@ -467,6 +468,7 @@ STATEFUL_RULE_GROUP_ARN=$(aws network-firewall create-rule-group \
--capacity 10 \
--rule-group '{"RulesSource": {"RulesString": "drop tls $HOME_NET any -> $EXTERNAL_NET any (ssl_state:client_hello; tls.sni; content:\"evil.com\"; startswith; nocase; endswith; msg:\"matching TLS denylisted FQDNs\"; priority:1; flow:to_server, established; sid:1; rev:1;)"}}' \
--description "Stateful rule group example" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-network-firewall-gs \
--query 'RuleGroupResponse.RuleGroupArn' \
--output text)
@@ -512,6 +514,7 @@ FIREWALL_POLICY_ARN=$(aws network-firewall create-firewall-policy \
]
}' \
--description "Firewall policy example" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-network-firewall-gs \
--query 'FirewallPolicyResponse.FirewallPolicyArn' \
--output text)
@@ -565,7 +568,8 @@ FIREWALL_OUTPUT=$(aws network-firewall create-firewall \
--firewall-name "$FIREWALL_NAME" \
--firewall-policy-arn "$FIREWALL_POLICY_ARN" \
--vpc-id "$VPC_ID" \
- --subnet-mappings "SubnetId=$SUBNET_ID")
+ --subnet-mappings "SubnetId=$SUBNET_ID" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-network-firewall-gs)
check_error "$FIREWALL_OUTPUT" "Create firewall"
echo "$FIREWALL_OUTPUT"
@@ -662,7 +666,7 @@ echo "(auto-confirmed)"
# Create a route table for the firewall endpoint
echo "Creating route table for firewall endpoint..."
-FIREWALL_ROUTE_TABLE_ID=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --query 'RouteTable.RouteTableId' --output text)
+FIREWALL_ROUTE_TABLE_ID=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications 'ResourceType=route-table,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-network-firewall-gs}]' --query 'RouteTable.RouteTableId' --output text)
if [ $? -ne 0 ] || [ -z "$FIREWALL_ROUTE_TABLE_ID" ]; then
echo "ERROR: Failed to create firewall route table"
diff --git a/tuts/048-amazon-simple-notification-service-gs/amazon-simple-notification-service-gs.sh b/tuts/048-amazon-simple-notification-service-gs/amazon-simple-notification-service-gs.sh
index e17ee0a..c908129 100644
--- a/tuts/048-amazon-simple-notification-service-gs/amazon-simple-notification-service-gs.sh
+++ b/tuts/048-amazon-simple-notification-service-gs/amazon-simple-notification-service-gs.sh
@@ -76,9 +76,13 @@ if [ ${#TOPIC_NAME} -gt 256 ]; then
handle_error "Topic name exceeds maximum length of 256 characters"
fi
-# Step 1: Create an SNS topic with cost optimization: no tags
+# Step 1: Create an SNS topic
echo "Creating SNS topic: $TOPIC_NAME"
-TOPIC_RESULT=$(aws sns create-topic --name "$TOPIC_NAME" --region "$AWS_REGION" --output json) || handle_error "Failed to create SNS topic"
+TOPIC_RESULT=$(aws sns create-topic \
+ --name "$TOPIC_NAME" \
+ --region "$AWS_REGION" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-simple-notification-service-gs \
+ --output json) || handle_error "Failed to create SNS topic"
# Extract the topic ARN using jq for reliable parsing
TOPIC_ARN=$(echo "$TOPIC_RESULT" | jq -r '.TopicArn // empty') || handle_error "Failed to parse topic result"
@@ -121,6 +125,14 @@ echo "Subscription created: $SUBSCRIPTION_ARN"
echo "A confirmation email has been sent to $EMAIL_ADDRESS"
echo ""
+# Tag the subscription
+if [ "$SUBSCRIPTION_ARN" != "PendingConfirmation" ] && [ "$SUBSCRIPTION_ARN" != "pending confirmation" ]; then
+ aws sns tag-resource \
+ --resource-arn "$SUBSCRIPTION_ARN" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-simple-notification-service-gs \
+ --region "$AWS_REGION" 2>/dev/null || echo "Warning: Failed to tag subscription"
+fi
+
# Step 3: List subscriptions to verify
echo "Listing subscriptions for topic: $TOPIC_ARN"
SUBSCRIPTIONS=$(aws sns list-subscriptions-by-topic --topic-arn "$TOPIC_ARN" --region "$AWS_REGION" --output json) || handle_error "Failed to list subscriptions"
diff --git a/tuts/049-aws-end-user-messaging-gs/aws-end-user-messaging-gs.sh b/tuts/049-aws-end-user-messaging-gs/aws-end-user-messaging-gs.sh
index 83802ef..b5cf00e 100644
--- a/tuts/049-aws-end-user-messaging-gs/aws-end-user-messaging-gs.sh
+++ b/tuts/049-aws-end-user-messaging-gs/aws-end-user-messaging-gs.sh
@@ -205,7 +205,7 @@ echo "Creating application with name: $APP_NAME"
# Step 1: Create an application
echo "Executing: aws pinpoint create-app --create-application-request Name=${APP_NAME}"
-CREATE_APP_OUTPUT=$(aws pinpoint create-app --create-application-request "Name=${APP_NAME}" 2>&1)
+CREATE_APP_OUTPUT=$(aws pinpoint create-app --create-application-request "Name=${APP_NAME},tags={project=doc-smith,tutorial=aws-end-user-messaging-gs}" 2>&1)
if ! check_error "$CREATE_APP_OUTPUT" "create-app"; then
exit 1
diff --git a/tuts/051-aws-direct-connect-gs/aws-direct-connect-gs.sh b/tuts/051-aws-direct-connect-gs/aws-direct-connect-gs.sh
index 666c9f2..6a50835 100755
--- a/tuts/051-aws-direct-connect-gs/aws-direct-connect-gs.sh
+++ b/tuts/051-aws-direct-connect-gs/aws-direct-connect-gs.sh
@@ -131,7 +131,8 @@ echo "Creating a dedicated connection at location $LOCATION_CODE with bandwidth
CONNECTION_OUTPUT=$(aws directconnect create-connection \
--location "$LOCATION_CODE" \
--bandwidth "1Gbps" \
- --connection-name "$CONNECTION_NAME")
+ --connection-name "$CONNECTION_NAME" \
+ --tags key=project,value=doc-smith key=tutorial,value=aws-direct-connect-gs)
check_error "$CONNECTION_OUTPUT" "create-connection"
echo "$CONNECTION_OUTPUT"
@@ -173,7 +174,8 @@ fi
# Step 6: Create a virtual private gateway (required for private virtual interface)
echo "Creating a virtual private gateway..."
-VGW_OUTPUT=$(aws ec2 create-vpn-gateway --type ipsec.1)
+VGW_OUTPUT=$(aws ec2 create-vpn-gateway --type ipsec.1 \
+ --tag-specifications 'ResourceType=vpn-gateway,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-direct-connect-gs}]')
check_error "$VGW_OUTPUT" "create-vpn-gateway"
echo "$VGW_OUTPUT"
diff --git a/tuts/052-aws-waf-gs/aws-waf-gs.sh b/tuts/052-aws-waf-gs/aws-waf-gs.sh
index baec70c..9a485cb 100644
--- a/tuts/052-aws-waf-gs/aws-waf-gs.sh
+++ b/tuts/052-aws-waf-gs/aws-waf-gs.sh
@@ -147,6 +147,7 @@ create_result=$(aws wafv2 create-web-acl \
--scope "CLOUDFRONT" \
--default-action Allow={} \
--visibility-config "SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=$METRIC_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-waf-gs \
--region us-east-1 2>&1) || handle_error "Failed to create Web ACL"
if ! validate_json "$create_result"; then
diff --git a/tuts/053-aws-config-gs/aws-config-gs.sh b/tuts/053-aws-config-gs/aws-config-gs.sh
old mode 100755
new mode 100644
index 06adb6b..b4fbb6f
--- a/tuts/053-aws-config-gs/aws-config-gs.sh
+++ b/tuts/053-aws-config-gs/aws-config-gs.sh
@@ -149,6 +149,9 @@ if [ "$BUCKET_IS_SHARED" = "false" ]; then
fi
check_command "$BUCKET_RESULT"
echo "S3 bucket created: $S3_BUCKET_NAME"
+
+ aws s3api put-bucket-tagging --bucket "$S3_BUCKET_NAME" --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-config-gs}]'
+ echo "Tags applied to S3 bucket"
else
echo "Using shared bucket: $S3_BUCKET_NAME (skipping creation)"
fi
@@ -162,7 +165,7 @@ echo "Public access blocked for bucket"
# Step 2: Create an SNS topic
TOPIC_NAME="config-topic-${RANDOM_ID}"
echo "Creating SNS topic: $TOPIC_NAME"
-SNS_RESULT=$(aws sns create-topic --name "$TOPIC_NAME")
+SNS_RESULT=$(aws sns create-topic --name "$TOPIC_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs)
check_command "$SNS_RESULT"
SNS_TOPIC_ARN=$(echo "$SNS_RESULT" | grep -o 'arn:aws:sns:[^"]*')
echo "SNS topic created: $SNS_TOPIC_ARN"
@@ -194,6 +197,9 @@ check_command "$ROLE_RESULT"
ROLE_ARN=$(echo "$ROLE_RESULT" | grep -o 'arn:aws:iam::[^"]*' | head -1)
echo "IAM role created: $ROLE_ARN"
+aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs
+echo "Tags applied to IAM role"
+
echo "Attaching AWS managed policy to role..."
ATTACH_RESULT=$(aws iam attach-role-policy --role-name "$ROLE_NAME" --policy-arn "$MANAGED_POLICY_ARN")
check_command "$ATTACH_RESULT"
@@ -283,6 +289,11 @@ RECORDER_RESULT=$(aws configservice put-configuration-recorder --configuration-r
check_command "$RECORDER_RESULT"
echo "Configuration recorder set up"
+if [ "$CREATED_NEW_CONFIG_RECORDER" = "true" ]; then
+ aws configservice tag-resource --resource-arn "arn:aws:config:${AWS_REGION}:${ACCOUNT_ID}:config-recorder/${CONFIG_RECORDER_NAME}" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs
+ echo "Tags applied to configuration recorder"
+fi
+
# Step 5: Check if delivery channel already exists
DELIVERY_CHANNEL_NAME="default"
CREATED_NEW_DELIVERY_CHANNEL="false"
@@ -332,6 +343,9 @@ EOF
CHANNEL_RESULT=$(aws configservice put-delivery-channel --delivery-channel file://deliveryChannel.json)
check_command "$CHANNEL_RESULT"
echo "Delivery channel created"
+
+ aws configservice tag-resource --resource-arn "arn:aws:config:${AWS_REGION}:${ACCOUNT_ID}:delivery-channel/${DELIVERY_CHANNEL_NAME}" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs
+ echo "Tags applied to delivery channel"
fi
# Step 6: Start the configuration recorder
@@ -381,4 +395,4 @@ else
echo "Resources will not be cleaned up. You can manually clean them up later."
fi
-echo "Script completed successfully!"
+echo "Script completed successfully!"
\ No newline at end of file
diff --git a/tuts/054-amazon-kinesis-video-streams-gs/amazon-kinesis-video-streams-gs.sh b/tuts/054-amazon-kinesis-video-streams-gs/amazon-kinesis-video-streams-gs.sh
index ec0ddee..eef24b4 100644
--- a/tuts/054-amazon-kinesis-video-streams-gs/amazon-kinesis-video-streams-gs.sh
+++ b/tuts/054-amazon-kinesis-video-streams-gs/amazon-kinesis-video-streams-gs.sh
@@ -97,7 +97,7 @@ echo "=========================================="
echo "Creating stream: $STREAM_NAME"
# Create the Kinesis video stream
-if ! CREATE_STREAM_OUTPUT=$(aws kinesisvideo create-stream --stream-name "$STREAM_NAME" --data-retention-in-hours 24 --output json 2>&1); then
+if ! CREATE_STREAM_OUTPUT=$(aws kinesisvideo create-stream --stream-name "$STREAM_NAME" --data-retention-in-hours 24 --tags project=doc-smith,tutorial=amazon-kinesis-video-streams-gs --output json 2>&1); then
handle_error "Failed to create stream: $CREATE_STREAM_OUTPUT"
fi
check_error "$CREATE_STREAM_OUTPUT" "create-stream"
diff --git a/tuts/055-amazon-vpc-lattice-gs/amazon-vpc-lattice-getting-started.sh b/tuts/055-amazon-vpc-lattice-gs/amazon-vpc-lattice-getting-started.sh
index 61d0a68..bf9056d 100644
--- a/tuts/055-amazon-vpc-lattice-gs/amazon-vpc-lattice-getting-started.sh
+++ b/tuts/055-amazon-vpc-lattice-gs/amazon-vpc-lattice-getting-started.sh
@@ -135,7 +135,7 @@ echo "Random ID for this session: ${RANDOM_ID}" | tee -a "$LOG_FILE"
echo -e "\n=== Step 1: Creating a VPC Lattice service network ===" | tee -a "$LOG_FILE"
echo "Creating service network: $SERVICE_NETWORK_NAME" | tee -a "$LOG_FILE"
-SERVICE_NETWORK_OUTPUT=$(log_command "aws vpc-lattice create-service-network --name '$SERVICE_NETWORK_NAME' --output json")
+SERVICE_NETWORK_OUTPUT=$(log_command "aws vpc-lattice create-service-network --name '$SERVICE_NETWORK_NAME' --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-vpc-lattice-gs --output json")
check_error $?
# Extract the service network ID using jq for safety
@@ -158,7 +158,7 @@ check_error $?
echo -e "\n=== Step 2: Creating a VPC Lattice service ===" | tee -a "$LOG_FILE"
echo "Creating service: $SERVICE_NAME" | tee -a "$LOG_FILE"
-SERVICE_OUTPUT=$(log_command "aws vpc-lattice create-service --name '$SERVICE_NAME' --output json")
+SERVICE_OUTPUT=$(log_command "aws vpc-lattice create-service --name '$SERVICE_NAME' --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-vpc-lattice-gs --output json")
check_error $?
# Extract the service ID using jq for safety
diff --git a/tuts/057-amazon-managed-streaming-for-apache-kafka-gs/amazon-managed-streaming-for-apache-kafka-gs.sh b/tuts/057-amazon-managed-streaming-for-apache-kafka-gs/amazon-managed-streaming-for-apache-kafka-gs.sh
index 4c8c7a6..78e302d 100755
--- a/tuts/057-amazon-managed-streaming-for-apache-kafka-gs/amazon-managed-streaming-for-apache-kafka-gs.sh
+++ b/tuts/057-amazon-managed-streaming-for-apache-kafka-gs/amazon-managed-streaming-for-apache-kafka-gs.sh
@@ -330,7 +330,8 @@ CLUSTER_RESPONSE=$(aws kafka create-cluster \
--broker-node-group-info "{\"InstanceType\": \"kafka.t3.small\", \"ClientSubnets\": [\"${SUBNET_ARRAY[0]}\", \"${SUBNET_ARRAY[1]}\", \"${SUBNET_ARRAY[2]}\"], \"SecurityGroups\": [\"$DEFAULT_SG\"]}" \
--kafka-version "3.6.0" \
--number-of-broker-nodes 3 \
- --encryption-info "{\"EncryptionInTransit\": {\"InCluster\": true, \"ClientBroker\": \"TLS\"}}" 2>&1)
+ --encryption-info "{\"EncryptionInTransit\": {\"InCluster\": true, \"ClientBroker\": \"TLS\"}}" \
+ --tags project=doc-smith,tutorial=amazon-managed-streaming-for-apache-kafka-gs 2>&1)
# Check if the command was successful
if [ $? -ne 0 ]; then
@@ -444,6 +445,9 @@ if [ -z "$POLICY_ARN" ]; then
handle_error "Failed to extract policy ARN from response: $POLICY_RESPONSE"
fi
+aws iam tag-policy --policy-arn "$POLICY_ARN" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-managed-streaming-for-apache-kafka-gs
+
echo "IAM policy created. ARN: $POLICY_ARN"
# Create IAM role for EC2
@@ -460,6 +464,8 @@ if [ $? -ne 0 ]; then
fi
echo "IAM role created: $ROLE_NAME"
+aws iam tag-role --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-managed-streaming-for-apache-kafka-gs
# Attach policy to role
echo "Attaching policy to role"
@@ -545,7 +551,8 @@ echo "Creating security group for client: $SG_NAME"
CLIENT_SG_RESPONSE=$(aws ec2 create-security-group \
--group-name "$SG_NAME" \
--description "Security group for MSK client" \
- --vpc-id "$DEFAULT_VPC_ID" 2>&1)
+ --vpc-id "$DEFAULT_VPC_ID" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-managed-streaming-for-apache-kafka-gs}]' 2>&1)
# Check if the command was successful
if [ $? -ne 0 ]; then
@@ -606,7 +613,7 @@ echo "Ingress rule added to MSK security group"
# Create key pair
KEY_NAME="MSKKeyPair-${RANDOM_SUFFIX}"
echo "Creating key pair: $KEY_NAME"
-KEY_RESPONSE=$(aws ec2 create-key-pair --key-name "$KEY_NAME" --query 'KeyMaterial' --output text 2>&1)
+KEY_RESPONSE=$(aws ec2 create-key-pair --key-name "$KEY_NAME" --tag-specifications 'ResourceType=key-pair,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-managed-streaming-for-apache-kafka-gs}]' --query 'KeyMaterial' --output text 2>&1)
# Check if the command was successful
if [ $? -ne 0 ]; then
@@ -646,7 +653,7 @@ INSTANCE_RESPONSE=$(aws ec2 run-instances \
--security-group-ids "$CLIENT_SG_ID" \
--subnet-id "$SELECTED_SUBNET_ID" \
--iam-instance-profile "Name=$INSTANCE_PROFILE_NAME" \
- --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=MSKTutorialClient-${RANDOM_SUFFIX}}]" 2>&1)
+ --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=MSKTutorialClient-${RANDOM_SUFFIX}},{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-managed-streaming-for-apache-kafka-gs}]" 2>&1)
# Check if the command was successful
if [ $? -ne 0 ]; then
diff --git a/tuts/058-elastic-load-balancing-gs/elastic-load-balancing-gs.sh b/tuts/058-elastic-load-balancing-gs/elastic-load-balancing-gs.sh
index 48523c3..289d240 100644
--- a/tuts/058-elastic-load-balancing-gs/elastic-load-balancing-gs.sh
+++ b/tuts/058-elastic-load-balancing-gs/elastic-load-balancing-gs.sh
@@ -143,6 +143,7 @@ SG_INFO=$(aws ec2 create-security-group \
--group-name "${RESOURCE_PREFIX}-sg" \
--description "Security group for ELB demo" \
--vpc-id "$VPC_ID" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=elastic-load-balancing-gs}]' \
--query "GroupId" --output text 2>/dev/null || echo "")
check_command "$SG_INFO"
SECURITY_GROUP_ID="$SG_INFO"
@@ -165,6 +166,7 @@ LB_INFO=$(aws elbv2 create-load-balancer \
--name "${RESOURCE_PREFIX}-lb" \
--subnets "${SUBNETS[0]}" "${SUBNETS[1]}" \
--security-groups "$SECURITY_GROUP_ID" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=elastic-load-balancing-gs \
--query "LoadBalancers[0].LoadBalancerArn" --output text 2>/dev/null || echo "")
check_command "$LB_INFO"
LOAD_BALANCER_ARN="$LB_INFO"
@@ -185,6 +187,7 @@ TG_INFO=$(aws elbv2 create-target-group \
--port 80 \
--vpc-id "$VPC_ID" \
--target-type instance \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=elastic-load-balancing-gs \
--query "TargetGroups[0].TargetGroupArn" --output text 2>/dev/null || echo "")
check_command "$TG_INFO"
TARGET_GROUP_ARN="$TG_INFO"
@@ -231,6 +234,7 @@ LISTENER_INFO=$(aws elbv2 create-listener \
--protocol HTTP \
--port 80 \
--default-actions Type=forward,TargetGroupArn="$TARGET_GROUP_ARN" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=elastic-load-balancing-gs \
--query "Listeners[0].ListenerArn" --output text 2>/dev/null || echo "")
check_command "$LISTENER_INFO"
LISTENER_ARN="$LISTENER_INFO"
diff --git a/tuts/059-amazon-datazone-gs/amazon-datazone-gs.sh b/tuts/059-amazon-datazone-gs/amazon-datazone-gs.sh
index 78ac00c..f183ec3 100755
--- a/tuts/059-amazon-datazone-gs/amazon-datazone-gs.sh
+++ b/tuts/059-amazon-datazone-gs/amazon-datazone-gs.sh
@@ -188,6 +188,8 @@ EOF
# Create the role
ROLE_CREATE=$(aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document file://trust-policy.json)
check_error "$ROLE_CREATE" "create-role"
+ aws iam tag-role --role-name "$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-datazone-gs
# FIX: Enhanced IAM role permissions for DataZone domain execution
# Attach necessary policies with more comprehensive permissions
@@ -232,6 +234,7 @@ DOMAIN_RESULT=$(aws datazone create-domain \
--name "$DOMAIN_NAME" \
--description "My first DataZone domain" \
--domain-execution-role "arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-datazone-gs \
--region "$REGION")
check_error "$DOMAIN_RESULT" "create-domain"
@@ -444,6 +447,8 @@ EOF
# Create the role
GLUE_ROLE_CREATE=$(aws iam create-role --role-name "$GLUE_ROLE_NAME" --assume-role-policy-document file://glue-trust-policy.json)
check_error "$GLUE_ROLE_CREATE" "create-glue-role"
+ aws iam tag-role --role-name "$GLUE_ROLE_NAME" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-datazone-gs
# Create policy document
cat > glue-policy.json << EOF
diff --git a/tuts/061-amazon-athena-gs/amazon-athena-gs.sh b/tuts/061-amazon-athena-gs/amazon-athena-gs.sh
index 0a95ce9..7e4291d 100644
--- a/tuts/061-amazon-athena-gs/amazon-athena-gs.sh
+++ b/tuts/061-amazon-athena-gs/amazon-athena-gs.sh
@@ -129,6 +129,10 @@ if [ "$BUCKET_IS_SHARED" = false ]; then
handle_error "Failed to create S3 bucket: $CREATE_BUCKET_RESULT"
fi
+ aws s3api put-bucket-tagging \
+ --bucket "$S3_BUCKET" \
+ --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-athena-gs}]'
+
# Security: Enable S3 bucket encryption with KMS validation
echo "Enabling default encryption on S3 bucket..."
if ! aws s3api put-bucket-encryption \
diff --git a/tuts/063-aws-iot-core-gs/aws-iot-core-gs.sh b/tuts/063-aws-iot-core-gs/aws-iot-core-gs.sh
index 5b7856a..91dd712 100755
--- a/tuts/063-aws-iot-core-gs/aws-iot-core-gs.sh
+++ b/tuts/063-aws-iot-core-gs/aws-iot-core-gs.sh
@@ -135,7 +135,7 @@ cat > iot-policy.json << EOF
EOF
echo "Creating IoT policy: $POLICY_NAME..." | tee -a $LOG_FILE
-log_cmd "aws iot create-policy --policy-name $POLICY_NAME --policy-document file://iot-policy.json"
+log_cmd "aws iot create-policy --policy-name $POLICY_NAME --policy-document file://iot-policy.json --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-core-gs"
check_error $?
# Create IoT thing
@@ -143,6 +143,9 @@ echo "Creating IoT thing: $THING_NAME..." | tee -a $LOG_FILE
log_cmd "aws iot create-thing --thing-name $THING_NAME"
check_error $?
+THING_ARN=$(aws iot describe-thing --thing-name "$THING_NAME" --query 'thingArn' --output text)
+aws iot tag-resource --resource-arn "$THING_ARN" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-core-gs
+
# Create directory for certificates
echo "Creating certificates directory..." | tee -a $LOG_FILE
log_cmd "mkdir -p $CERTS_DIR"
@@ -265,7 +268,7 @@ cat > shared-sub-policy.json << EOF
}
EOF
-log_cmd "aws iot create-policy --policy-name $SHARED_POLICY_NAME --policy-document file://shared-sub-policy.json"
+log_cmd "aws iot create-policy --policy-name $SHARED_POLICY_NAME --policy-document file://shared-sub-policy.json --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-core-gs"
check_error $?
log_cmd "aws iot attach-policy --policy-name $SHARED_POLICY_NAME --target $CERTIFICATE_ARN"
diff --git a/tuts/064-amazon-neptune-gs/amazon-neptune-gs.sh b/tuts/064-amazon-neptune-gs/amazon-neptune-gs.sh
index 4872d2f..00f83b4 100755
--- a/tuts/064-amazon-neptune-gs/amazon-neptune-gs.sh
+++ b/tuts/064-amazon-neptune-gs/amazon-neptune-gs.sh
@@ -83,7 +83,7 @@ echo "Security Group Name: $SG_NAME" | tee -a "$LOG_FILE"
# Step 1: Create VPC
echo "Creating VPC..." | tee -a "$LOG_FILE"
-VPC_OUTPUT=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=$VPC_NAME}]" --output json)
+VPC_OUTPUT=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=$VPC_NAME},{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-neptune-gs}]" --output json)
check_error "$VPC_OUTPUT" $? "Failed to create VPC"
VPC_ID=$(echo "$VPC_OUTPUT" | grep -o '"VpcId": "[^"]*' | cut -d'"' -f4)
@@ -95,7 +95,7 @@ log_cmd "aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames"
# Step 2: Create Internet Gateway and attach to VPC
echo "Creating Internet Gateway..." | tee -a "$LOG_FILE"
-IGW_OUTPUT=$(aws ec2 create-internet-gateway --output json)
+IGW_OUTPUT=$(aws ec2 create-internet-gateway --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-neptune-gs}]' --output json)
check_error "$IGW_OUTPUT" $? "Failed to create Internet Gateway"
IGW_ID=$(echo "$IGW_OUTPUT" | grep -o '"InternetGatewayId": "[^"]*' | cut -d'"' -f4)
@@ -116,15 +116,15 @@ AZ2=$(echo "$AZ_OUTPUT" | grep -o '"ZoneName": "[^"]*' | cut -d'"' -f4 | head -2
AZ3=$(echo "$AZ_OUTPUT" | grep -o '"ZoneName": "[^"]*' | cut -d'"' -f4 | head -3 | tail -1)
# Create 3 subnets in different AZs
-SUBNET1_OUTPUT=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.1.0/24 --availability-zone $AZ1 --output json)
+SUBNET1_OUTPUT=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.1.0/24 --availability-zone $AZ1 --tag-specifications 'ResourceType=subnet,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-neptune-gs}]' --output json)
check_error "$SUBNET1_OUTPUT" $? "Failed to create subnet 1"
SUBNET1_ID=$(echo "$SUBNET1_OUTPUT" | grep -o '"SubnetId": "[^"]*' | cut -d'"' -f4)
-SUBNET2_OUTPUT=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.2.0/24 --availability-zone $AZ2 --output json)
+SUBNET2_OUTPUT=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.2.0/24 --availability-zone $AZ2 --tag-specifications 'ResourceType=subnet,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-neptune-gs}]' --output json)
check_error "$SUBNET2_OUTPUT" $? "Failed to create subnet 2"
SUBNET2_ID=$(echo "$SUBNET2_OUTPUT" | grep -o '"SubnetId": "[^"]*' | cut -d'"' -f4)
-SUBNET3_OUTPUT=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.3.0/24 --availability-zone $AZ3 --output json)
+SUBNET3_OUTPUT=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.3.0/24 --availability-zone $AZ3 --tag-specifications 'ResourceType=subnet,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-neptune-gs}]' --output json)
check_error "$SUBNET3_OUTPUT" $? "Failed to create subnet 3"
SUBNET3_ID=$(echo "$SUBNET3_OUTPUT" | grep -o '"SubnetId": "[^"]*' | cut -d'"' -f4)
@@ -133,7 +133,7 @@ echo "Created subnets: $SUBNET1_ID, $SUBNET2_ID, $SUBNET3_ID" | tee -a "$LOG_FIL
# Step 4: Create route table and add route to Internet Gateway
echo "Creating route table..." | tee -a "$LOG_FILE"
-ROUTE_TABLE_OUTPUT=$(aws ec2 create-route-table --vpc-id $VPC_ID --output json)
+ROUTE_TABLE_OUTPUT=$(aws ec2 create-route-table --vpc-id $VPC_ID --tag-specifications 'ResourceType=route-table,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-neptune-gs}]' --output json)
check_error "$ROUTE_TABLE_OUTPUT" $? "Failed to create route table"
ROUTE_TABLE_ID=$(echo "$ROUTE_TABLE_OUTPUT" | grep -o '"RouteTableId": "[^"]*' | cut -d'"' -f4)
@@ -149,7 +149,7 @@ log_cmd "aws ec2 associate-route-table --route-table-id $ROUTE_TABLE_ID --subnet
# Step 5: Create security group
echo "Creating security group..." | tee -a "$LOG_FILE"
-SG_OUTPUT=$(aws ec2 create-security-group --group-name $SG_NAME --description "Security group for Neptune" --vpc-id $VPC_ID --output json)
+SG_OUTPUT=$(aws ec2 create-security-group --group-name $SG_NAME --description "Security group for Neptune" --vpc-id $VPC_ID --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-neptune-gs}]' --output json)
check_error "$SG_OUTPUT" $? "Failed to create security group"
SECURITY_GROUP_ID=$(echo "$SG_OUTPUT" | grep -o '"GroupId": "[^"]*' | cut -d'"' -f4)
@@ -162,19 +162,19 @@ log_cmd "aws ec2 authorize-security-group-ingress --group-id $SECURITY_GROUP_ID
# Step 6: Create DB subnet group
echo "Creating DB subnet group..." | tee -a "$LOG_FILE"
-DB_SUBNET_GROUP_OUTPUT=$(aws neptune create-db-subnet-group --db-subnet-group-name $DB_SUBNET_GROUP --db-subnet-group-description "Subnet group for Neptune" --subnet-ids $SUBNET1_ID $SUBNET2_ID $SUBNET3_ID --output json)
+DB_SUBNET_GROUP_OUTPUT=$(aws neptune create-db-subnet-group --db-subnet-group-name $DB_SUBNET_GROUP --db-subnet-group-description "Subnet group for Neptune" --subnet-ids $SUBNET1_ID $SUBNET2_ID $SUBNET3_ID --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-neptune-gs --output json)
check_error "$DB_SUBNET_GROUP_OUTPUT" $? "Failed to create DB subnet group"
echo "DB subnet group created: $DB_SUBNET_GROUP" | tee -a "$LOG_FILE"
# Step 7: Create Neptune DB cluster
echo "Creating Neptune DB cluster..." | tee -a "$LOG_FILE"
-DB_CLUSTER_OUTPUT=$(aws neptune create-db-cluster --db-cluster-identifier $DB_CLUSTER_ID --engine neptune --vpc-security-group-ids $SECURITY_GROUP_ID --db-subnet-group-name $DB_SUBNET_GROUP --output json)
+DB_CLUSTER_OUTPUT=$(aws neptune create-db-cluster --db-cluster-identifier $DB_CLUSTER_ID --engine neptune --vpc-security-group-ids $SECURITY_GROUP_ID --db-subnet-group-name $DB_SUBNET_GROUP --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-neptune-gs --output json)
check_error "$DB_CLUSTER_OUTPUT" $? "Failed to create Neptune DB cluster"
echo "Neptune DB cluster created: $DB_CLUSTER_ID" | tee -a "$LOG_FILE"
# Step 8: Create Neptune DB instance
echo "Creating Neptune DB instance..." | tee -a "$LOG_FILE"
-DB_INSTANCE_OUTPUT=$(aws neptune create-db-instance --db-instance-identifier $DB_INSTANCE_ID --db-instance-class db.r5.large --engine neptune --db-cluster-identifier $DB_CLUSTER_ID --output json)
+DB_INSTANCE_OUTPUT=$(aws neptune create-db-instance --db-instance-identifier $DB_INSTANCE_ID --db-instance-class db.r5.large --engine neptune --db-cluster-identifier $DB_CLUSTER_ID --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-neptune-gs --output json)
check_error "$DB_INSTANCE_OUTPUT" $? "Failed to create Neptune DB instance"
echo "Neptune DB instance created: $DB_INSTANCE_ID" | tee -a "$LOG_FILE"
diff --git a/tuts/065-amazon-elasticache-gs/amazon-elasticache-gs.sh b/tuts/065-amazon-elasticache-gs/amazon-elasticache-gs.sh
index 2d37cac..cf79280 100644
--- a/tuts/065-amazon-elasticache-gs/amazon-elasticache-gs.sh
+++ b/tuts/065-amazon-elasticache-gs/amazon-elasticache-gs.sh
@@ -4,7 +4,7 @@
# This script creates a Valkey serverless cache, configures security groups,
# and demonstrates how to connect to and use the cache.
-set -euo pipefail
+set -uo pipefail
# Set up logging
LOG_FILE="elasticache_tutorial_$(date +%Y%m%d_%H%M%S).log"
@@ -117,7 +117,8 @@ echo ""
echo "Step 2: Creating Valkey serverless cache..."
if ! CREATE_RESULT=$(aws elasticache create-serverless-cache \
--serverless-cache-name "$CACHE_NAME" \
- --engine valkey 2>&1); then
+ --engine valkey \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-elasticache-gs 2>&1); then
handle_error "Failed to create serverless cache: $CREATE_RESULT"
fi
diff --git a/tuts/066-amazon-cognito-gs/amazon-cognito-gs.sh b/tuts/066-amazon-cognito-gs/amazon-cognito-gs.sh
index 34c1964..4d82847 100644
--- a/tuts/066-amazon-cognito-gs/amazon-cognito-gs.sh
+++ b/tuts/066-amazon-cognito-gs/amazon-cognito-gs.sh
@@ -157,6 +157,11 @@ fi
echo "User Pool created with ID: $USER_POOL_ID"
+USER_POOL_ARN=$(echo "$USER_POOL_OUTPUT" | jq -r '.UserPool.Arn // empty')
+aws cognito-idp tag-resource \
+ --resource-arn "$USER_POOL_ARN" \
+ --tags project=doc-smith,tutorial=amazon-cognito-gs
+
# Wait for user pool to be ready
echo "Waiting for user pool to be ready..."
sleep 5
diff --git a/tuts/067-aws-payment-cryptography-gs/aws-payment-cryptography-gs.sh b/tuts/067-aws-payment-cryptography-gs/aws-payment-cryptography-gs.sh
index ff4c663..19ece20 100644
--- a/tuts/067-aws-payment-cryptography-gs/aws-payment-cryptography-gs.sh
+++ b/tuts/067-aws-payment-cryptography-gs/aws-payment-cryptography-gs.sh
@@ -64,7 +64,8 @@ log "Starting AWS Payment Cryptography tutorial"
log "Step 1: Creating a card verification key (CVK)"
if ! KEY_OUTPUT=$(aws payment-cryptography create-key \
--exportable \
- --key-attributes KeyAlgorithm=TDES_2KEY,KeyUsage=TR31_C0_CARD_VERIFICATION_KEY,KeyClass=SYMMETRIC_KEY,KeyModesOfUse='{Generate=true,Verify=true}' 2>&1); then
+ --key-attributes KeyAlgorithm=TDES_2KEY,KeyUsage=TR31_C0_CARD_VERIFICATION_KEY,KeyClass=SYMMETRIC_KEY,KeyModesOfUse='{Generate=true,Verify=true}' \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-payment-cryptography-gs 2>&1); then
handle_error "Failed to create key"
fi
diff --git a/tuts/069-aws-fault-injection-service-gs/aws-fault-injection-service-getting-started.sh b/tuts/069-aws-fault-injection-service-gs/aws-fault-injection-service-getting-started.sh
index 6eab00b..e16187a 100644
--- a/tuts/069-aws-fault-injection-service-gs/aws-fault-injection-service-getting-started.sh
+++ b/tuts/069-aws-fault-injection-service-gs/aws-fault-injection-service-getting-started.sh
@@ -117,6 +117,7 @@ FIS_ROLE_OUTPUT=$(aws iam create-role \
--role-name "$FIS_ROLE_NAME" \
--assume-role-policy-document file://fis-trust-policy.json)
check_error "$FIS_ROLE_OUTPUT" "aws iam create-role"
+aws iam tag-role --role-name "$FIS_ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-fault-injection-service-gs
CREATED_RESOURCES+=("IAM Role: $FIS_ROLE_NAME")
# Create policy document for SSM actions
@@ -169,6 +170,7 @@ EC2_ROLE_OUTPUT=$(aws iam create-role \
--role-name "$EC2_ROLE_NAME" \
--assume-role-policy-document file://ec2-trust-policy.json)
check_error "$EC2_ROLE_OUTPUT" "aws iam create-role"
+aws iam tag-role --role-name "$EC2_ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-fault-injection-service-gs
CREATED_RESOURCES+=("IAM Role: $EC2_ROLE_NAME")
# Attach SSM policy to the EC2 role
@@ -214,7 +216,7 @@ INSTANCE_OUTPUT=$(aws ec2 run-instances \
--image-id "$AMI_ID" \
--instance-type t2.micro \
--iam-instance-profile Name="$INSTANCE_PROFILE_NAME" \
- --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=FIS-Test-Instance}]')
+ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=FIS-Test-Instance},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-fault-injection-service-gs}]')
check_error "$INSTANCE_OUTPUT" "aws ec2 run-instances"
# Get instance ID
@@ -350,7 +352,9 @@ cat > experiment-template.json << EOF
],
"roleArn": "$ROLE_ARN",
"tags": {
- "Name": "FIS-CPU-Stress-Experiment"
+ "Name": "FIS-CPU-Stress-Experiment",
+ "project": "doc-smith",
+ "tutorial": "aws-fault-injection-service-gs"
}
}
EOF
diff --git a/tuts/070-amazon-dynamodb-gs/amazon-dynamodb-gs.sh b/tuts/070-amazon-dynamodb-gs/amazon-dynamodb-gs.sh
index 967dfca..de19e5f 100644
--- a/tuts/070-amazon-dynamodb-gs/amazon-dynamodb-gs.sh
+++ b/tuts/070-amazon-dynamodb-gs/amazon-dynamodb-gs.sh
@@ -9,7 +9,7 @@
# - Querying data in the table
# - Deleting the table (cleanup)
-set -euo pipefail
+set -uo pipefail
# Set up logging with secure permissions
LOG_DIR="${XDG_STATE_HOME:-.}/dynamodb-tutorial-logs"
@@ -141,7 +141,8 @@ CREATE_TABLE_OUTPUT=$(aws dynamodb create-table \
AttributeName=SongTitle,AttributeType=S \
--key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST \
- --table-class STANDARD 2>&1) || {
+ --table-class STANDARD \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-dynamodb-gs 2>&1) || {
echo "ERROR: Failed to create table" >&2
exit 1
}
diff --git a/tuts/073-aws-secrets-manager-gs/aws-secrets-manager-gs.sh b/tuts/073-aws-secrets-manager-gs/aws-secrets-manager-gs.sh
index 136fb81..9c17941 100644
--- a/tuts/073-aws-secrets-manager-gs/aws-secrets-manager-gs.sh
+++ b/tuts/073-aws-secrets-manager-gs/aws-secrets-manager-gs.sh
@@ -130,6 +130,7 @@ ADMIN_ROLE_OUTPUT=$(aws iam create-role \
check_error "$ADMIN_ROLE_OUTPUT" "create-role for admin"
echo "$ADMIN_ROLE_OUTPUT"
+aws iam tag-role --role-name "$ADMIN_ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-secrets-manager-gs
# Attach the SecretsManagerReadWrite policy to the admin role
echo "Attaching SecretsManagerReadWrite policy to admin role"
@@ -148,6 +149,7 @@ RUNTIME_ROLE_OUTPUT=$(aws iam create-role \
check_error "$RUNTIME_ROLE_OUTPUT" "create-role for runtime"
echo "$RUNTIME_ROLE_OUTPUT"
+aws iam tag-role --role-name "$RUNTIME_ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-secrets-manager-gs
# Wait for roles to be fully created
echo "Waiting for IAM roles to be fully created..."
@@ -168,7 +170,8 @@ CREATE_SECRET_OUTPUT=$(aws secretsmanager create-secret \
--name "$SECRET_NAME" \
--description "API key for my application" \
--secret-string "$SECRET_VALUE" \
- --add-replica-regions 'Region=us-east-1' 2>&1)
+ --add-replica-regions 'Region=us-east-1' \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-secrets-manager-gs 2>&1)
check_error "$CREATE_SECRET_OUTPUT" "create-secret"
echo "$CREATE_SECRET_OUTPUT"
diff --git a/tuts/074-amazon-textract-gs/amazon-textract-getting-started.sh b/tuts/074-amazon-textract-gs/amazon-textract-getting-started.sh
index f28d80b..ca1d3ef 100644
--- a/tuts/074-amazon-textract-gs/amazon-textract-getting-started.sh
+++ b/tuts/074-amazon-textract-gs/amazon-textract-getting-started.sh
@@ -113,6 +113,10 @@ if [ "$BUCKET_IS_SHARED" = false ]; then
echo "$CREATE_BUCKET_OUTPUT"
check_error $CREATE_BUCKET_STATUS "$CREATE_BUCKET_OUTPUT" "aws s3 mb s3://$BUCKET_NAME"
+ aws s3api put-bucket-tagging \
+ --bucket "$BUCKET_NAME" \
+ --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-textract-gs}]'
+
# Apply security settings to bucket
aws s3api put-bucket-versioning --bucket "$BUCKET_NAME" --versioning-configuration Status=Enabled 2>&1 || true
aws s3api put-bucket-encryption --bucket "$BUCKET_NAME" --server-side-encryption-configuration '{"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}]}' 2>&1 || true
diff --git a/tuts/075-aws-database-migration-service-gs/aws-database-migration-service-gs.sh b/tuts/075-aws-database-migration-service-gs/aws-database-migration-service-gs.sh
old mode 100755
new mode 100644
index b267971..7f06f32
--- a/tuts/075-aws-database-migration-service-gs/aws-database-migration-service-gs.sh
+++ b/tuts/075-aws-database-migration-service-gs/aws-database-migration-service-gs.sh
@@ -278,7 +278,6 @@ cleanup_resources() {
aws rds delete-db-parameter-group --db-parameter-group-name "$DB_PARAM_GROUP_POSTGRES"
fi
- # FIX: Added cleanup for DB subnet group
if [ -n "$DB_SUBNET_GROUP" ]; then
echo "Deleting DB subnet group..."
aws rds delete-db-subnet-group --db-subnet-group-name "$DB_SUBNET_GROUP"
@@ -341,7 +340,7 @@ DB_PASSWORD=$(generate_password)
# Store password in AWS Secrets Manager
echo "Creating secret for database password..."
SECRET_NAME="dms-tutorial-db-password-$RANDOM_ID"
-SECRET_ARN=$(aws secretsmanager create-secret --name "$SECRET_NAME" --secret-string "$DB_PASSWORD" --query 'ARN' --output text)
+SECRET_ARN=$(aws secretsmanager create-secret --name "$SECRET_NAME" --secret-string "$DB_PASSWORD" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs --query 'ARN' --output text)
check_status
echo "Database password stored in Secrets Manager with ARN: $SECRET_ARN"
@@ -497,7 +496,7 @@ fi
if [ "$USING_EXISTING_VPC" = false ]; then
echo "Creating new VPC..."
- VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.1.0/24 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=DMSVPC}]' --query 'Vpc.VpcId' --output text)
+ VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.1.0/24 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=DMSVPC},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'Vpc.VpcId' --output text)
check_status
echo "VPC created with ID: $VPC_ID"
@@ -506,24 +505,24 @@ if [ "$USING_EXISTING_VPC" = false ]; then
check_status
echo "Creating subnets..."
- PUBLIC_SUBNET_1_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.0/26 --availability-zone "$AZ1" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-public-subnet-1}]' --query 'Subnet.SubnetId' --output text)
+ PUBLIC_SUBNET_1_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.0/26 --availability-zone "$AZ1" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-public-subnet-1},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'Subnet.SubnetId' --output text)
check_status
echo "Public subnet 1 created with ID: $PUBLIC_SUBNET_1_ID"
- PUBLIC_SUBNET_2_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.64/26 --availability-zone "$AZ2" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-public-subnet-2}]' --query 'Subnet.SubnetId' --output text)
+ PUBLIC_SUBNET_2_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.64/26 --availability-zone "$AZ2" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-public-subnet-2},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'Subnet.SubnetId' --output text)
check_status
echo "Public subnet 2 created with ID: $PUBLIC_SUBNET_2_ID"
- PRIVATE_SUBNET_1_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.128/26 --availability-zone "$AZ1" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-private-subnet-1}]' --query 'Subnet.SubnetId' --output text)
+ PRIVATE_SUBNET_1_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.128/26 --availability-zone "$AZ1" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-private-subnet-1},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'Subnet.SubnetId' --output text)
check_status
echo "Private subnet 1 created with ID: $PRIVATE_SUBNET_1_ID"
- PRIVATE_SUBNET_2_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.192/26 --availability-zone "$AZ2" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-private-subnet-2}]' --query 'Subnet.SubnetId' --output text)
+ PRIVATE_SUBNET_2_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.192/26 --availability-zone "$AZ2" --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=DMSVPC-private-subnet-2},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'Subnet.SubnetId' --output text)
check_status
echo "Private subnet 2 created with ID: $PRIVATE_SUBNET_2_ID"
echo "Creating internet gateway..."
- IGW_ID=$(aws ec2 create-internet-gateway --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=DMSVPC-igw}]' --query 'InternetGateway.InternetGatewayId' --output text)
+ IGW_ID=$(aws ec2 create-internet-gateway --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=DMSVPC-igw},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'InternetGateway.InternetGatewayId' --output text)
check_status
echo "Internet gateway created with ID: $IGW_ID"
@@ -532,7 +531,7 @@ if [ "$USING_EXISTING_VPC" = false ]; then
check_status
echo "Creating route table..."
- PUBLIC_RT_ID=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=DMSVPC-public-rt}]' --query 'RouteTable.RouteTableId' --output text)
+ PUBLIC_RT_ID=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=DMSVPC-public-rt},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'RouteTable.RouteTableId' --output text)
check_status
echo "Route table created with ID: $PUBLIC_RT_ID"
@@ -569,7 +568,8 @@ echo "Creating MariaDB parameter group: $DB_PARAM_GROUP_MARIADB"
aws rds create-db-parameter-group \
--db-parameter-group-name "$DB_PARAM_GROUP_MARIADB" \
--db-parameter-group-family mariadb10.6 \
- --description "Group for specifying binary log settings for replication"
+ --description "Group for specifying binary log settings for replication" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs
check_status
echo "Modifying MariaDB parameters..."
@@ -584,7 +584,8 @@ echo "Creating PostgreSQL parameter group: $DB_PARAM_GROUP_POSTGRES"
aws rds create-db-parameter-group \
--db-parameter-group-name "$DB_PARAM_GROUP_POSTGRES" \
--db-parameter-group-family postgres16 \
- --description "Group for specifying role setting for replication"
+ --description "Group for specifying role setting for replication" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs
check_status
echo "Modifying PostgreSQL parameters..."
@@ -593,13 +594,13 @@ aws rds modify-db-parameter-group \
--parameters "ParameterName=session_replication_role,ParameterValue=replica,ApplyMethod=immediate"
check_status
-# FIX: Create a custom DB subnet group instead of using the default one
echo "Creating DB subnet group..."
DB_SUBNET_GROUP="dms-db-subnet-group-$RANDOM_ID"
aws rds create-db-subnet-group \
--db-subnet-group-name "$DB_SUBNET_GROUP" \
--db-subnet-group-description "DB subnet group for DMS tutorial" \
- --subnet-ids "$PUBLIC_SUBNET_1_ID" "$PUBLIC_SUBNET_2_ID"
+ --subnet-ids "$PUBLIC_SUBNET_1_ID" "$PUBLIC_SUBNET_2_ID" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs
check_status
echo "DB subnet group created: $DB_SUBNET_GROUP"
# Step 3: Create Your Source Amazon RDS Database (MariaDB)
@@ -623,7 +624,8 @@ aws rds create-db-instance \
--db-name dms_sample \
--backup-retention-period 1 \
--no-auto-minor-version-upgrade \
- --publicly-accessible
+ --publicly-accessible \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs
check_status
echo "Waiting for MariaDB instance to be available..."
@@ -650,7 +652,8 @@ aws rds create-db-instance \
--db-name dms_sample \
--backup-retention-period 0 \
--no-auto-minor-version-upgrade \
- --publicly-accessible
+ --publicly-accessible \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs
check_status
echo "Waiting for PostgreSQL instance to be available..."
@@ -672,7 +675,7 @@ echo "Using AMI: $AMI_ID"
# Create a key pair
KEY_NAME="DMSKeyPair-$RANDOM_ID"
echo "Creating key pair: $KEY_NAME"
-aws ec2 create-key-pair --key-name "$KEY_NAME" --query 'KeyMaterial' --output text > "${KEY_NAME}.pem"
+aws ec2 create-key-pair --key-name "$KEY_NAME" --tag-specifications 'ResourceType=key-pair,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' --query 'KeyMaterial' --output text > "${KEY_NAME}.pem"
check_status
chmod 400 "${KEY_NAME}.pem"
echo "Key pair created and saved to ${KEY_NAME}.pem"
@@ -695,7 +698,7 @@ EC2_INSTANCE_ID=$(aws ec2 run-instances \
--key-name "$KEY_NAME" \
--subnet-id "$PUBLIC_SUBNET_1_ID" \
--security-group-ids "$SG_ID" \
- --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=DMSClient}]' \
+ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=DMSClient},{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-database-migration-service-gs}]' \
--associate-public-ip-address \
--query 'Instances[0].InstanceId' \
--output text)
@@ -801,7 +804,8 @@ if [[ "${RUN_MIGRATION,,}" == "y" ]]; then
aws dms create-replication-subnet-group \
--replication-subnet-group-identifier "$DMS_SUBNET_GROUP" \
--replication-subnet-group-description "DMS subnet group" \
- --subnet-ids "$PUBLIC_SUBNET_1_ID" "$PUBLIC_SUBNET_2_ID"
+ --subnet-ids "$PUBLIC_SUBNET_1_ID" "$PUBLIC_SUBNET_2_ID" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs
check_status
# Create a replication instance
@@ -814,7 +818,8 @@ if [[ "${RUN_MIGRATION,,}" == "y" ]]; then
--vpc-security-group-ids "$SG_ID" \
--replication-subnet-group-identifier "$DMS_SUBNET_GROUP" \
--availability-zone "$AZ1" \
- --no-publicly-accessible
+ --no-publicly-accessible \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs
check_status
echo "Waiting for DMS replication instance to be available..."
@@ -865,6 +870,7 @@ if [[ "${RUN_MIGRATION,,}" == "y" ]]; then
--server-name "$MARIADB_ENDPOINT" \
--port 3306 \
--database-name dms_sample \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs \
--query 'Endpoint.EndpointArn' \
--output text)
check_status
@@ -882,6 +888,7 @@ if [[ "${RUN_MIGRATION,,}" == "y" ]]; then
--server-name "$POSTGRES_ENDPOINT" \
--port 5432 \
--database-name dms_sample \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs \
--query 'Endpoint.EndpointArn' \
--output text)
check_status
@@ -964,6 +971,7 @@ if [[ "${RUN_MIGRATION,,}" == "y" ]]; then
--migration-type full-load-and-cdc \
--table-mappings "$TABLE_MAPPINGS" \
--replication-task-settings "$TASK_SETTINGS" \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-database-migration-service-gs \
--query 'ReplicationTask.ReplicationTaskArn' \
--output text)
check_status
@@ -995,9 +1003,10 @@ if [[ "${RUN_MIGRATION,,}" == "y" ]]; then
echo "Migration task started. Initial replication will take some time to complete."
else
- echo "Step 10: Skipping DMS migration task creation (as requested)"
- echo "========================================================"
- echo "Infrastructure is ready. You can create migration tasks later as needed."
+ echo ""
+ echo "✗ Skipping DMS migration setup"
+ echo "=============================="
+ echo "Infrastructure is ready. You can create DMS resources later as needed."
echo ""
fi
@@ -1066,4 +1075,4 @@ print_resources
cleanup_resources
echo "Script completed successfully."
-exit 0
+exit 0
\ No newline at end of file
diff --git a/tuts/077-aws-account-management-gs/aws-account-management-gs.sh b/tuts/077-aws-account-management-gs/aws-account-management-gs.sh
index 1d5166c..d596131 100644
--- a/tuts/077-aws-account-management-gs/aws-account-management-gs.sh
+++ b/tuts/077-aws-account-management-gs/aws-account-management-gs.sh
@@ -44,6 +44,9 @@ MAX_RETRIES=3
RETRY_DELAY=2
API_CALL_DELAY=0.5
+# Tagging configuration
+TAGS_KEY_VALUE="Key=project,Value=doc-smith Key=tutorial,Value=aws-account-management-gs"
+
# Function to handle errors safely
handle_error() {
local message="${1:-Error encountered}"
@@ -310,6 +313,10 @@ done
echo "- Sequential API execution to prevent rate limit errors"
echo "- Applied rate limiting between API calls"
echo ""
+ echo "Tagging configuration applied:"
+ echo "- Project tag: doc-smith"
+ echo "- Tutorial tag: aws-account-management-gs"
+ echo ""
echo "See $LOG_FILE for detailed logs."
} | tee -a "$LOG_FILE"
diff --git a/tuts/078-amazon-elastic-container-registry-gs/amazon-elastic-container-registry-gs.sh b/tuts/078-amazon-elastic-container-registry-gs/amazon-elastic-container-registry-gs.sh
index aad9bb9..5655c0c 100755
--- a/tuts/078-amazon-elastic-container-registry-gs/amazon-elastic-container-registry-gs.sh
+++ b/tuts/078-amazon-elastic-container-registry-gs/amazon-elastic-container-registry-gs.sh
@@ -159,7 +159,7 @@ fi
# Create ECR repository
echo "Creating ECR repository..."
-REPO_RESULT=$(aws ecr create-repository --repository-name hello-repository)
+REPO_RESULT=$(aws ecr create-repository --repository-name hello-repository --tags key=project,value=doc-smith key=tutorial,value=amazon-elastic-container-registry-gs)
if [[ -z "$REPO_RESULT" || "$REPO_RESULT" == *"error"* ]]; then
handle_error "Failed to create ECR repository"
fi
diff --git a/tuts/079-aws-iot-device-defender-gs/aws-iot-device-defender-gs.sh b/tuts/079-aws-iot-device-defender-gs/aws-iot-device-defender-gs.sh
index b9fea7d..33d31c5 100644
--- a/tuts/079-aws-iot-device-defender-gs/aws-iot-device-defender-gs.sh
+++ b/tuts/079-aws-iot-device-defender-gs/aws-iot-device-defender-gs.sh
@@ -114,6 +114,8 @@ create_iam_role() {
return 1
fi
+ aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs 2>&1 || true
+
# For IoT logging role, create an inline policy instead of using a managed policy
if [[ "$ROLE_NAME" == "AWSIoTLoggingRole" ]]; then
local LOGGING_POLICY
@@ -377,6 +379,9 @@ fi
echo "Audit task started with ID: $TASK_ID"
CREATED_RESOURCES+=("Audit Task: $TASK_ID")
+# Tag the audit task via IoT service
+aws iot tag-resource --resource-arn "arn:aws:iot:$(aws configure get region):${ACCOUNT_ID}:audittask/${TASK_ID}" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs 2>&1 || true
+
# Wait for the audit task to complete
echo "Waiting for audit task to complete (this may take a few minutes)..."
TASK_STATUS="IN_PROGRESS"
@@ -486,6 +491,7 @@ if validate_json "$MITIGATION_RESULT"; then
MITIGATION_ACTION_ARN=$(extract_json_value "$MITIGATION_RESULT" "actionArn")
if [ -n "$MITIGATION_ACTION_ARN" ]; then
echo "Mitigation Action ARN: $MITIGATION_ACTION_ARN"
+ aws iot tag-resource --resource-arn "$MITIGATION_ACTION_ARN" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs 2>&1 || true
fi
else
echo "WARNING: Could not validate mitigation action response, but action may have been created"
@@ -565,7 +571,7 @@ if [ -n "$TOPIC_ARN" ]; then
echo "Topic ARN: $TOPIC_ARN"
else
echo "Creating SNS topic for notifications..."
- SNS_RESULT=$(aws sns create-topic --name "IoTDDNotifications" --output json 2>&1) || true
+ SNS_RESULT=$(aws sns create-topic --name "IoTDDNotifications" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs --output json 2>&1) || true
if ! check_error "$SNS_RESULT"; then
echo "WARNING: Failed to create SNS topic, continuing..."
diff --git a/tuts/080-aws-step-functions-gs/aws-step-functions-gs.sh b/tuts/080-aws-step-functions-gs/aws-step-functions-gs.sh
index b18e79d..532c213 100644
--- a/tuts/080-aws-step-functions-gs/aws-step-functions-gs.sh
+++ b/tuts/080-aws-step-functions-gs/aws-step-functions-gs.sh
@@ -371,6 +371,7 @@ ROLE_RESULT=$(aws iam create-role \
check_api_error "$ROLE_RESULT" "Create IAM role"
echo "Role created successfully"
+aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-step-functions-gs
# Get the role ARN
ROLE_ARN=$(extract_json_field "$ROLE_RESULT" ".Role.Arn")
@@ -435,7 +436,8 @@ SM_RESULT=$(aws stepfunctions create-state-machine \
--name "$STATE_MACHINE_NAME" \
--definition file://hello-world.json \
--role-arn "$ROLE_ARN" \
- --type STANDARD 2>&1)
+ --type STANDARD \
+ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-step-functions-gs 2>&1)
check_api_error "$SM_RESULT" "Create state machine"
echo "State machine created successfully"
diff --git a/tuts/081-aws-elemental-mediaconnect-gs/aws-elemental-mediaconnect-gs.sh b/tuts/081-aws-elemental-mediaconnect-gs/aws-elemental-mediaconnect-gs.sh
index b7806f7..1d2c058 100644
--- a/tuts/081-aws-elemental-mediaconnect-gs/aws-elemental-mediaconnect-gs.sh
+++ b/tuts/081-aws-elemental-mediaconnect-gs/aws-elemental-mediaconnect-gs.sh
@@ -18,6 +18,9 @@ exec > >(tee -a "$LOG_FILE") 2>&1
echo "Starting AWS Elemental MediaConnect tutorial script at $(date)"
echo "All commands and outputs will be logged to $LOG_FILE"
+# Tags for all resources
+TAGS_ARRAY=("Key=project,Value=doc-smith" "Key=tutorial,Value=aws-elemental-mediaconnect-gs")
+
# Function to handle errors
handle_error() {
echo "ERROR: $1" >&2
@@ -71,6 +74,18 @@ extract_json_value() {
fi
}
+# Function to tag MediaConnect resource
+tag_mediaconnect_resource() {
+ local resource_arn="$1"
+ echo "Tagging resource: $resource_arn"
+
+ for tag in "${TAGS_ARRAY[@]}"; do
+ if ! aws mediaconnect tag-resource --resource-arn "$resource_arn" --tags "$tag" 2>&1; then
+ echo "WARNING: Failed to apply tag $tag to resource"
+ fi
+ done
+}
+
# Function to clean up resources
cleanup_resources() {
echo "Cleaning up resources..."
@@ -206,6 +221,9 @@ if [[ ! "$FLOW_ARN" =~ ^arn:aws:mediaconnect:[a-z0-9-]+:[0-9]+:flow:[a-zA-Z0-9:-
handle_error "Invalid Flow ARN format: $FLOW_ARN"
fi
+# Tag the flow
+tag_mediaconnect_resource "$FLOW_ARN"
+
# Step 3: Add an output
echo "Step 3: Adding an output to the flow..."
add_output_output=""
@@ -226,6 +244,7 @@ if [ -z "$output_arn" ]; then
else
OUTPUT_ARN="$output_arn"
echo "Output ARN: $OUTPUT_ARN"
+ tag_mediaconnect_resource "$OUTPUT_ARN"
fi
# Step 4: Grant an entitlement
@@ -250,6 +269,7 @@ if [ -z "$entitlement_arn" ]; then
else
ENTITLEMENT_ARN="$entitlement_arn"
echo "Entitlement ARN: $ENTITLEMENT_ARN"
+ tag_mediaconnect_resource "$ENTITLEMENT_ARN"
fi
# Step 5: List entitlements to share with affiliates
diff --git a/tuts/082-amazon-polly-gs/amazon-polly-getting-started.sh b/tuts/082-amazon-polly-gs/amazon-polly-getting-started.sh
index 9a4b12f..8025dba 100644
--- a/tuts/082-amazon-polly-gs/amazon-polly-getting-started.sh
+++ b/tuts/082-amazon-polly-gs/amazon-polly-getting-started.sh
@@ -161,7 +161,13 @@ EOF
# Upload the lexicon
echo "Uploading lexicon..." | tee -a "$LOG_FILE"
-log_cmd "aws polly put-lexicon --name '$LEXICON_NAME' --content file://'$LEXICON_FILE'" || true
+LEXICON_ARN=$(aws polly put-lexicon --name "$LEXICON_NAME" --content file://"$LEXICON_FILE" --query 'LexiconArn' --output text 2>&1) || true
+if [[ -n "$LEXICON_ARN" && "$LEXICON_ARN" != "" && ! "$LEXICON_ARN" =~ error ]]; then
+ echo "Lexicon uploaded with ARN: $LEXICON_ARN" | tee -a "$LOG_FILE"
+ aws polly tag-resource --resource-arn "$LEXICON_ARN" --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-polly-gs 2>&1 | tee -a "$LOG_FILE" || true
+else
+ echo "Lexicon uploaded." | tee -a "$LOG_FILE"
+fi
# List available lexicons
echo "Listing available lexicons..." | tee -a "$LOG_FILE"
diff --git a/tuts/085-amazon-ecs-service-connect/amazon-ecs-service-connect.sh b/tuts/085-amazon-ecs-service-connect/amazon-ecs-service-connect.sh
index 813ab62..a15c99a 100755
--- a/tuts/085-amazon-ecs-service-connect/amazon-ecs-service-connect.sh
+++ b/tuts/085-amazon-ecs-service-connect/amazon-ecs-service-connect.sh
@@ -130,7 +130,8 @@ setup_default_vpc_infrastructure() {
SG_OUTPUT=$(aws ec2 create-security-group \
--group-name "${ENV_PREFIX}-ecs-sg-${RANDOM_SUFFIX}" \
--description "Security group for ECS Service Connect tutorial" \
- --vpc-id "$VPC_ID" 2>&1)
+ --vpc-id "$VPC_ID" \
+ --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-ecs-service-connect}]' 2>&1)
check_for_errors "$SG_OUTPUT" "create-security-group"
SECURITY_GROUP_ID=$(echo "$SG_OUTPUT" | grep -o '"GroupId": "[^"]*"' | cut -d'"' -f4)
track_resource "SG:$SECURITY_GROUP_ID"
@@ -157,7 +158,7 @@ create_log_groups() {
log "Creating CloudWatch log groups..."
# Create log group for nginx container
- aws logs create-log-group --log-group-name "/ecs/service-connect-nginx" 2>&1 | grep -v "ResourceAlreadyExistsException" || {
+ aws logs create-log-group --log-group-name "/ecs/service-connect-nginx" --tags project=doc-smith,tutorial=amazon-ecs-service-connect 2>&1 | grep -v "ResourceAlreadyExistsException" || {
if [ ${PIPESTATUS[0]} -eq 0 ]; then
log "Log group /ecs/service-connect-nginx created"
track_resource "LOG_GROUP:/ecs/service-connect-nginx"
@@ -167,7 +168,7 @@ create_log_groups() {
}
# Create log group for service connect proxy
- aws logs create-log-group --log-group-name "/ecs/service-connect-proxy" 2>&1 | grep -v "ResourceAlreadyExistsException" || {
+ aws logs create-log-group --log-group-name "/ecs/service-connect-proxy" --tags project=doc-smith,tutorial=amazon-ecs-service-connect 2>&1 | grep -v "ResourceAlreadyExistsException" || {
if [ ${PIPESTATUS[0]} -eq 0 ]; then
log "Log group /ecs/service-connect-proxy created"
track_resource "LOG_GROUP:/ecs/service-connect-proxy"
@@ -184,7 +185,7 @@ create_ecs_cluster() {
CLUSTER_OUTPUT=$(aws ecs create-cluster \
--cluster-name "$CLUSTER_NAME" \
--service-connect-defaults namespace="$NAMESPACE_NAME" \
- --tags key=Environment,value=tutorial 2>&1)
+ --tags key=Environment,value=tutorial key=project,value=doc-smith key=tutorial,value=amazon-ecs-service-connect 2>&1)
check_for_errors "$CLUSTER_OUTPUT" "create-cluster"
track_resource "CLUSTER:$CLUSTER_NAME"
@@ -228,6 +229,7 @@ create_iam_roles() {
--role-name ecsTaskExecutionRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy >/dev/null 2>&1
track_resource "ROLE:ecsTaskExecutionRole"
+ aws iam tag-role --role-name ecsTaskExecutionRole --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-ecs-service-connect
log "Created ecsTaskExecutionRole"
sleep 10
fi
@@ -259,6 +261,7 @@ EOF
--assume-role-policy-document file:///tmp/ecs-task-trust-policy.json >/dev/null
track_resource "IAM_ROLE:ecsTaskRole"
+ aws iam tag-role --role-name ecsTaskRole --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-ecs-service-connect
log "Created ecsTaskRole"
# Wait for role to be available
@@ -363,6 +366,14 @@ create_ecs_service() {
{
"key": "Environment",
"value": "tutorial"
+ },
+ {
+ "key": "project",
+ "value": "doc-smith"
+ },
+ {
+ "key": "tutorial",
+ "value": "amazon-ecs-service-connect"
}
]
}
diff --git a/tuts/086-amazon-ecs-fargate-linux/amazon-ecs-fargate-linux.sh b/tuts/086-amazon-ecs-fargate-linux/amazon-ecs-fargate-linux.sh
index 49ca735..03cb4ab 100644
--- a/tuts/086-amazon-ecs-fargate-linux/amazon-ecs-fargate-linux.sh
+++ b/tuts/086-amazon-ecs-fargate-linux/amazon-ecs-fargate-linux.sh
@@ -311,6 +311,8 @@ EOF
execute_command "aws iam create-role --role-name ecsTaskExecutionRole --assume-role-policy-document file://trust-policy.json" "Create ECS task execution role"
+ aws iam tag-role --role-name ecsTaskExecutionRole --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-ecs-fargate-linux
+
execute_command "aws iam attach-role-policy --role-name ecsTaskExecutionRole --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" "Attach ECS task execution policy"
# Clean up temporary file securely
@@ -325,7 +327,7 @@ echo "==========================================="
echo "STEP 2: CREATE ECS CLUSTER"
echo "==========================================="
-CLUSTER_OUTPUT=$(execute_command "aws ecs create-cluster --cluster-name '$CLUSTER_NAME'" "Create ECS cluster")
+CLUSTER_OUTPUT=$(execute_command "aws ecs create-cluster --cluster-name '$CLUSTER_NAME' --tags key=project,value=doc-smith key=tutorial,value=amazon-ecs-fargate-linux" "Create ECS cluster")
check_for_aws_errors "$CLUSTER_OUTPUT" "Create ECS cluster"
CREATED_RESOURCES+=("ECS Cluster: $CLUSTER_NAME")
@@ -413,7 +415,7 @@ echo "Using default VPC: $VPC_ID"
# Create security group with restricted access
# Note: This allows HTTP access from anywhere for demo purposes
# In production, restrict source to specific IP ranges or security groups
-SECURITY_GROUP_OUTPUT=$(execute_command "aws ec2 create-security-group --group-name '$SECURITY_GROUP_NAME' --description 'Security group for ECS Fargate tutorial - HTTP access' --vpc-id '$VPC_ID'" "Create security group")
+SECURITY_GROUP_OUTPUT=$(execute_command "aws ec2 create-security-group --group-name '$SECURITY_GROUP_NAME' --description 'Security group for ECS Fargate tutorial - HTTP access' --vpc-id '$VPC_ID' --tag-specifications 'ResourceType=security-group,Tags=[{Key=project,Value=doc-smith},{Key=tutorial,Value=amazon-ecs-fargate-linux}]'" "Create security group")
check_for_aws_errors "$SECURITY_GROUP_OUTPUT" "Create security group"
SECURITY_GROUP_ID=$(echo "$SECURITY_GROUP_OUTPUT" | grep -o '"GroupId": "[^"]*"' | head -1 | cut -d'"' -f4)
@@ -461,7 +463,7 @@ echo "STEP 5: CREATE ECS SERVICE"
echo "==========================================="
# Create the service with proper JSON formatting for network configuration
-SERVICE_CMD="aws ecs create-service --cluster '$CLUSTER_NAME' --service-name '$SERVICE_NAME' --task-definition '$TASK_FAMILY' --desired-count 1 --launch-type FARGATE --network-configuration '{\"awsvpcConfiguration\":{\"subnets\":[\"$(echo "$SUBNET_IDS_COMMA" | sed 's/,/","/g')\"],\"securityGroups\":[\"$SECURITY_GROUP_ID\"],\"assignPublicIp\":\"ENABLED\"}}'"
+SERVICE_CMD="aws ecs create-service --cluster '$CLUSTER_NAME' --service-name '$SERVICE_NAME' --task-definition '$TASK_FAMILY' --desired-count 1 --launch-type FARGATE --network-configuration '{\"awsvpcConfiguration\":{\"subnets\":[\"$(echo "$SUBNET_IDS_COMMA" | sed 's/,/","/g')\"],\"securityGroups\":[\"$SECURITY_GROUP_ID\"],\"assignPublicIp\":\"ENABLED\"}}' --tags key=project,value=doc-smith key=tutorial,value=amazon-ecs-fargate-linux"
echo "Service creation command: $SERVICE_CMD"
diff --git a/tuts/087-apigateway-lambda-integration/apigateway-lambda-integration.sh b/tuts/087-apigateway-lambda-integration/apigateway-lambda-integration.sh
index 1c9f3f7..bf2daf0 100644
--- a/tuts/087-apigateway-lambda-integration/apigateway-lambda-integration.sh
+++ b/tuts/087-apigateway-lambda-integration/apigateway-lambda-integration.sh
@@ -127,6 +127,8 @@ aws iam create-role \
exit 1
}
+aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=apigateway-lambda-integration
+
# Attach execution policy
aws iam attach-role-policy \
--role-name "$ROLE_NAME" \
@@ -149,7 +151,8 @@ aws lambda create-function \
--zip-file fileb://function.zip \
--timeout 30 \
--memory-size 128 \
- --environment "Variables={LOG_LEVEL=INFO}" || {
+ --environment "Variables={LOG_LEVEL=INFO}" \
+ --tags project=doc-smith,tutorial=apigateway-lambda-integration || {
echo "Error: Failed to create Lambda function" >&2
exit 1
}
@@ -161,6 +164,7 @@ API_RESPONSE=$(aws apigateway create-rest-api \
--name "$API_NAME" \
--endpoint-configuration types=REGIONAL \
--description "API for Lambda proxy integration tutorial" \
+ --tags project=doc-smith,tutorial=apigateway-lambda-integration \
--output json)
API_ID=$(echo "$API_RESPONSE" | grep -o '"id": "[^"]*"' | head -1 | cut -d'"' -f4)