请求编写AWS环境校验Bash脚本(含PASS/FAIL判定)
AWS资源自动校验Bash脚本实现
输入文件格式
支持CSV或JSON两种格式,用于指定要校验的AWS账号、区域和资源筛选标签:
CSV示例
account_id,region,tag_key,tag_value,expected_ec2_type,expected_vpc_cidr 123456789012,us-east-1,Environment,Production,t3.medium,10.0.0.0/16 987654321098,eu-west-1,Project,MyApp,t3.small,192.168.0.0/16
JSON示例
[ { "account_id": "123456789012", "region": "us-east-1", "tag_key": "Environment", "tag_value": "Production", "expected_ec2_type": "t3.medium", "expected_vpc_cidr": "10.0.0.0/16" } ]
核心校验脚本
#!/bin/bash set -eo pipefail # 配置预期校验规则(可根据需求修改) EXPECTED_EC2_TERMINATION_PROTECTION="enabled" EXPECTED_VPC_DNS_HOSTNAMES="enabled" EXPECTED_S3_DEFAULT_ENCRYPTION="AES256" EXPECTED_RDS_ENGINE_VERSION="8.0.mysql_aurora.3.03.2" EXPECTED_REDIS_ENGINE_VERSION="7.0" # 输出文件初始化 OUTPUT_FILE="aws-resource-validation-results.csv" echo "timestamp,account_id,region,resource_type,resource_id,check_item,status,details" > $OUTPUT_FILE # 日志函数 log_result() { local timestamp=$(date +"%Y-%m-%d %H:%M:%S") echo "$timestamp,$1,$2,$3,$4,$5,$6,$7" >> $OUTPUT_FILE } # 切换AWS账号(假设使用STS AssumeRole,需提前配置权限) switch_account() { local account_id=$1 local region=$2 # 替换为你的角色ARN模板 local role_arn="arn:aws:iam::${account_id}:role/ResourceValidationRole" local session_name="validation-session-$(date +%s)" # 获取临时凭证 local creds=$(aws sts assume-role --role-arn $role_arn --role-session-name $session_name --output json) export AWS_ACCESS_KEY_ID=$(echo $creds | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(echo $creds | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(echo $creds | jq -r '.Credentials.SessionToken') export AWS_DEFAULT_REGION=$region } # 校验EC2实例 check_ec2() { local account_id=$1 local region=$2 local tag_key=$3 local tag_value=$4 local expected_type=$5 # 获取符合标签的EC2实例 local instances=$(aws ec2 describe-instances --filters "Name=tag:$tag_key,Values=$tag_value" --output json) echo $instances | jq -r '.Reservations[].Instances[] | .InstanceId + "," + .InstanceType + "," + (.DisableApiTermination | tostring) + "," + .PrivateIpAddress' | while IFS=, read -r instance_id instance_type termination_protection private_ip; do # 校验实例类型 if [ "$instance_type" = "$expected_type" ]; then log_result $account_id $region "EC2" $instance_id "Instance Type" "PASS" "Expected: $expected_type, Actual: $instance_type" else log_result $account_id $region "EC2" $instance_id "Instance Type" "FAIL" "Expected: $expected_type, Actual: $instance_type" fi # 校验终止保护 if [ "$termination_protection" = "$EXPECTED_EC2_TERMINATION_PROTECTION" ]; then log_result $account_id $region "EC2" $instance_id "Termination Protection" "PASS" "Expected: $EXPECTED_EC2_TERMINATION_PROTECTION, Actual: $termination_protection" else log_result $account_id $region "EC2" $instance_id "Termination Protection" "FAIL" "Expected: $EXPECTED_EC2_TERMINATION_PROTECTION, Actual: $termination_protection" fi # 校验私有IP(可根据实际规则调整) log_result $account_id $region "EC2" $instance_id "Private IP" "PASS" "IP: $private_ip" done } # 校验VPC及子网 check_vpc() { local account_id=$1 local region=$2 local tag_key=$3 local tag_value=$4 local expected_cidr=$5 # 获取符合标签的VPC local vpcs=$(aws ec2 describe-vpcs --filters "Name=tag:$tag_key,Values=$tag_value" --output json) echo $vpcs | jq -r '.Vpcs[] | .VpcId + "," + .CidrBlock + "," + (.EnableDnsHostnames | tostring)' | while IFS=, read -r vpc_id cidr dns_hostnames; do # 校验VPC CIDR if [ "$cidr" = "$expected_cidr" ]; then log_result $account_id $region "VPC" $vpc_id "CIDR Block" "PASS" "Expected: $expected_cidr, Actual: $cidr" else log_result $account_id $region "VPC" $vpc_id "CIDR Block" "FAIL" "Expected: $expected_cidr, Actual: $cidr" fi # 校验DNS主机名状态 if [ "$dns_hostnames" = "$EXPECTED_VPC_DNS_HOSTNAMES" ]; then log_result $account_id $region "VPC" $vpc_id "DNS Hostnames" "PASS" "Expected: $EXPECTED_VPC_DNS_HOSTNAMES, Actual: $dns_hostnames" else log_result $account_id $region "VPC" $vpc_id "DNS Hostnames" "FAIL" "Expected: $EXPECTED_VPC_DNS_HOSTNAMES, Actual: $dns_hostnames" fi # 校验子网CIDR归属 local subnets=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$vpc_id" --output json) echo $subnets | jq -r '.Subnets[] | .SubnetId + "," + .CidrBlock' | while IFS=, read -r subnet_id subnet_cidr; do if [[ $subnet_cidr == $expected_cidr* ]]; then log_result $account_id $region "Subnet" $subnet_id "CIDR Block" "PASS" "Subnet CIDR: $subnet_cidr (within VPC CIDR $expected_cidr)" else log_result $account_id $region "Subnet" $subnet_id "CIDR Block" "FAIL" "Subnet CIDR: $subnet_cidr (not within VPC CIDR $expected_cidr)" fi done done } # 校验S3存储桶 check_s3() { local account_id=$1 local region=$2 local tag_key=$3 local tag_value=$4 # 获取符合标签的S3桶 local buckets=$(aws s3api list-buckets --output json | jq -r '.Buckets[] | .Name') for bucket in $buckets; do # 检查桶标签 local tags=$(aws s3api get-bucket-tagging --bucket $bucket --output json 2>/dev/null || echo '{"TagSet":[]}') local has_tag=$(echo $tags | jq -r --arg k "$tag_key" --arg v "$tag_value" '.TagSet[] | select(.Key == $k and .Value == $v) | .Key') if [ -z "$has_tag" ]; then continue fi # 校验桶名称前缀规则 if [[ $bucket == "prod-"* ]]; then log_result $account_id $region "S3" $bucket "Bucket Name" "PASS" "Name: $bucket (matches prefix rule)" else log_result $account_id $region "S3" $bucket "Bucket Name" "FAIL" "Name: $bucket (does not match prefix rule)" fi # 校验默认加密 local encryption=$(aws s3api get-bucket-encryption --bucket $bucket --output json 2>/dev/null || echo '{}') local encryption_type=$(echo $encryption | jq -r '.ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault.SSEAlgorithm' || echo "None") if [ "$encryption_type" = "$EXPECTED_S3_DEFAULT_ENCRYPTION" ]; then log_result $account_id $region "S3" $bucket "Default Encryption" "PASS" "Type: $encryption_type" else log_result $account_id $region "S3" $bucket "Default Encryption" "FAIL" "Expected: $EXPECTED_S3_DEFAULT_ENCRYPTION, Actual: $encryption_type" fi # 校验复制规则 local replication=$(aws s3api get-bucket-replication --bucket $bucket --output json 2>/dev/null || echo '{}') local replication_enabled=$(echo $replication | jq -r '.ReplicationConfiguration.Rules[] | .Status' || echo "Disabled") if [ "$replication_enabled" = "Enabled" ]; then log_result $account_id $region "S3" $bucket "Replication Rule" "PASS" "Status: Enabled" else log_result $account_id $region "S3" $bucket "Replication Rule" "FAIL" "Status: $replication_enabled" fi done } # 校验RDS实例 check_rds() { local account_id=$1 local region=$2 local tag_key=$3 local tag_value=$4 # 获取符合标签的RDS实例 local rds_instances=$(aws rds describe-db-instances --filters "Name=tag:$tag_key,Values=$tag_value" --output json) echo $rds_instances | jq -r '.DBInstances[] | .DBInstanceIdentifier + "," + .DBInstanceArn + "," + .Endpoint.Address + "," + .EngineVersion + "," + .DBInstanceStatus' | while IFS=, read -r rds_id arn endpoint version status; do # 校验ARN格式 if [[ $arn == "arn:aws:rds:$region:$account_id:db:"* ]]; then log_result $account_id $region "RDS" $rds_id "ARN Format" "PASS" "ARN: $arn" else log_result $account_id $region "RDS" $rds_id "ARN Format" "FAIL" "ARN: $arn (invalid format)" fi # 校验引擎版本 if [ "$version" = "$EXPECTED_RDS_ENGINE_VERSION" ]; then log_result $account_id $region "RDS" $rds_id "Engine Version" "PASS" "Expected: $EXPECTED_RDS_ENGINE_VERSION, Actual: $version" else log_result $account_id $region "RDS" $rds_id "Engine Version" "FAIL" "Expected: $EXPECTED_RDS_ENGINE_VERSION, Actual: $version" fi # 校验主实例状态 if [ "$status" = "available" ]; then log_result $account_id $region "RDS" $rds_id "Primary Instance Status" "PASS" "Status: $status" else log_result $account_id $region "RDS" $rds_id "Primary Instance Status" "FAIL" "Status: $status" fi done } # 校验Redis(ElastiCache) check_redis() { local account_id=$1 local region=$2 local tag_key=$3 local tag_value=$4 # 获取符合标签的Redis集群 local redis_clusters=$(aws elasticache describe-cache-clusters --filters "Name=tag:$tag_key,Values=$tag_value" --show-cache-node-info --output json) echo $redis_clusters | jq -r '.CacheClusters[] | .CacheClusterId + "," + .EngineVersion + "," + .CacheNodeType + "," + (.NumCacheNodes | tostring)' | while IFS=, read -r redis_id version node_type node_count; do # 校验引擎版本 if [[ $version == "$EXPECTED_REDIS_ENGINE_VERSION"* ]]; then log_result $account_id $region "Redis" $redis_id "Engine Version" "PASS" "Expected: $EXPECTED_REDIS_ENGINE_VERSION, Actual: $version" else log_result $account_id $region "Redis" $redis_id "Engine Version" "FAIL" "Expected: $EXPECTED_REDIS_ENGINE_VERSION, Actual: $version" fi # 校验节点类型 if [ "$node_type" = "cache.t3.medium" ]; then log_result $account_id $region "Redis" $redis_id "Node Type" "PASS" "Type: $node_type" else log_result $account_id $region "Redis" $redis_id "Node Type" "FAIL" "Expected: cache.t3.medium, Actual: $node_type" fi # 校验节点数量 if [ "$node_count" -ge 2 ]; then log_result $account_id $region "Redis" $redis_id "Node Count" "PASS" "Count: $node_count" else log_result $account_id $region "Redis" $redis_id "Node Count" "FAIL" "Expected: >=2, Actual: $node_count" fi done } # 校验ALB check_alb() { local account_id=$1 local region=$2 local tag_key=$3 local tag_value=$4 # 获取符合标签的ALB local albs=$(aws elbv2 describe-load-balancers --filters "Name=tag:$tag_key,Values=$tag_value" --output json) echo $albs | jq -r '.LoadBalancers[] | .LoadBalancerArn + "," + .DNSName' | while IFS=, read -r alb_arn dns_name; do # 校验DNS名称格式 if [[ $dns_name == *.elb.amazonaws.com ]]; then log_result $account_id $region "ALB" $alb_arn "DNS Name" "PASS" "DNS: $dns_name" else log_result $account_id $region "ALB" $alb_arn "DNS Name" "FAIL" "DNS: $dns_name (invalid format)" fi # 校验HTTPS监听器 local listeners=$(aws elbv2 describe-listeners --load-balancer-arn $alb_arn --output json) local has_https=$(echo $listeners | jq -r '.Listeners[] | select(.Protocol == "HTTPS") | .Protocol') if [ -n "$has_https" ]; then log_result $account_id $region "ALB" $alb_arn "HTTPS Listener" "PASS" "HTTPS listener exists" else log_result $account_id $region "ALB" $alb_arn "HTTPS Listener" "FAIL" "HTTPS listener not found" fi done } # 解析输入文件并执行校验 process_input() { local input_file=$1 if [[ $input_file == *.json ]]; then # 处理JSON输入 jq -r '.[] | [.account_id, .region, .tag_key, .tag_value, .expected_ec2_type, .expected_vpc_cidr] | @csv' $input_file | while IFS=, read -r account_id region tag_key tag_value expected_ec2_type expected_vpc_cidr; do echo "Processing account $account_id in region $region..." switch_account $account_id $region check_ec2 $account_id $region $tag_key $tag_value $expected_ec2_type check_vpc $account_id $region $tag_key $tag_value $expected_vpc_cidr check_s3 $account_id $region $tag_key $tag_value check_rds $account_id $region $tag_key $tag_value check_redis $account_id $region $tag_key $tag_value check_alb $account_id $region $tag_key $tag_value done elif [[ $input_file == *.csv ]]; then # 处理CSV输入(跳过表头) tail -n +2 $input_file | while IFS=, read -r account_id region tag_key tag_value expected_ec2_type expected_vpc_cidr; do echo "Processing account $account_id in region $region..." switch_account $account_id $region check_ec2 $account_id $region $tag_key $tag_value $expected_ec2_type check_vpc $account_id $region $tag_key $tag_value $expected_vpc_cidr check_s3 $account_id $region $tag_key $tag_value check_rds $account_id $region $tag
相关产品推荐
相关产品推荐

