How To Auto Update AWS SSM Agent Using SSM State Manager
Hello Everyone
Welcome to CloudAffaire and this is Debjeet.
In the last blog post, we have discussed how to patch a Windows instance using AWS SSM Patch Manager.
https://cloudaffaire.com/how-to-patch-a-windows-instance-using-aws-ssm-patch-manager/
In this blog post, we will discuss how to auto update AWS SSM agent using SSM state manager.
What Is AWS SSM State Manager:
AWS Systems Manager State Manager is a secure and scalable configuration management service that automates the process of keeping your Amazon EC2 and hybrid infrastructure in a state that you define. Using AWS SSM State Manager you can bootstrap instances with specific software at start-up, download and update agents on a defined schedule, including SSM Agent, configure network settings, join instances to a Windows domain (Windows Server instances only), patch instances with software updates throughout their lifecycle or run scripts on Linux and Windows managed instances throughout their lifecycle. State Manager integrates with AWS CloudTrail to provide a record of all executions that you can audit, and Amazon EventBridge to track state changes. You can also choose to store and view detailed command output in Amazon S3.
What Is AWS SSM State Manager Association:
A State Manager association is a configuration that is assigned to your managed instances. The configuration defines the state that you want to maintain on your instances. For example, an association can specify that antivirus software must be installed and running on your instances, or that certain ports must be closed. The association specifies a schedule for when the configuration is applied once or reapplied at specified times. The association also specifies actions to take when applying the configuration. For example, an association for antivirus software might run once a day. If the software is not installed, then State Manager installs it. If the software is installed, but the service is not running, then the association might instruct the State Manager to start the service.
How To Auto Update AWS SSM Agent Using SSM State Manager:
Requirements:
AWS CLI installed and configured. You can follow the below blog post to install and configure AWS CLI.
https://cloudaffaire.com/how-to-install-aws-cli/
https://cloudaffaire.com/how-to-configure-aws-cli/
Step 1: Create an EC2 SSM Managed Instance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
############################################################## ## How To Auto Update AWS SSM Agent Using SSM State Manager ## ############################################################## ## -------------------------------------- ## Create An AWS EC2 SSM Managed Instance ## -------------------------------------- ## Create a directory for this demo mkdir ssmdemo && cd ssmdemo ## Create a VPC AWS_VPC_ID=$(aws ec2 create-vpc \ --cidr-block 10.0.0.0/16 \ --query 'Vpc.{VpcId:VpcId}' \ --output text) ## Enable DNS hostname for your VPC aws ec2 modify-vpc-attribute \ --vpc-id $AWS_VPC_ID \ --enable-dns-hostnames "{\"Value\":true}" ## Create a public subnet AWS_SUBNET_PUBLIC_ID=$(aws ec2 create-subnet \ --vpc-id $AWS_VPC_ID --cidr-block 10.0.1.0/24 \ --availability-zone ap-south-1a --query 'Subnet.{SubnetId:SubnetId}' \ --output text) ## Enable Auto-assign Public IP on Public Subnet aws ec2 modify-subnet-attribute \ --subnet-id $AWS_SUBNET_PUBLIC_ID \ --map-public-ip-on-launch ## Create an Internet Gateway AWS_INTERNET_GATEWAY_ID=$(aws ec2 create-internet-gateway \ --query 'InternetGateway.{InternetGatewayId:InternetGatewayId}' \ --output text) ## Attach Internet gateway to your VPC aws ec2 attach-internet-gateway \ --vpc-id $AWS_VPC_ID \ --internet-gateway-id $AWS_INTERNET_GATEWAY_ID ## Create a route table AWS_CUSTOM_ROUTE_TABLE_ID=$(aws ec2 create-route-table \ --vpc-id $AWS_VPC_ID \ --query 'RouteTable.{RouteTableId:RouteTableId}' \ --output text ) ## Create route to Internet Gateway aws ec2 create-route \ --route-table-id $AWS_CUSTOM_ROUTE_TABLE_ID \ --destination-cidr-block 0.0.0.0/0 \ --gateway-id $AWS_INTERNET_GATEWAY_ID ## Associate the public subnet with route table AWS_ROUTE_TABLE_ASSOID=$(aws ec2 associate-route-table \ --subnet-id $AWS_SUBNET_PUBLIC_ID \ --route-table-id $AWS_CUSTOM_ROUTE_TABLE_ID \ --output text) ## Create a security group aws ec2 create-security-group \ --vpc-id $AWS_VPC_ID \ --group-name myvpc-security-group \ --description 'My VPC non default security group' ## Get security group ID's AWS_DEFAULT_SECURITY_GROUP_ID=$(aws ec2 describe-security-groups \ --filters "Name=vpc-id,Values=$AWS_VPC_ID" \ --query 'SecurityGroups[?GroupName == `default`].GroupId' \ --output text) && AWS_CUSTOM_SECURITY_GROUP_ID=$(aws ec2 describe-security-groups \ --filters "Name=vpc-id,Values=$AWS_VPC_ID" \ --query 'SecurityGroups[?GroupName == `myvpc-security-group`].GroupId' \ --output text) ## Create security group ingress rules aws ec2 authorize-security-group-ingress \ --group-id $AWS_CUSTOM_SECURITY_GROUP_ID \ --ip-permissions '[{"IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "IpRanges": [{"CidrIp": "0.0.0.0/0", "Description": "Allow SSH"}]}]' && aws ec2 authorize-security-group-ingress \ --group-id $AWS_CUSTOM_SECURITY_GROUP_ID \ --ip-permissions '[{"IpProtocol": "tcp", "FromPort": 80, "ToPort": 80, "IpRanges": [{"CidrIp": "0.0.0.0/0", "Description": "Allow HTTP"}]}]' ## Get Amazon Linux 2 latest AMI ID AWS_AMI_ID=$(aws ec2 describe-images \ --owners 'amazon' \ --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????-x86_64-gp2' 'Name=state,Values=available' \ --query 'sort_by(Images, &CreationDate)[-1].[ImageId]' \ --output 'text') ## Create a key-pair aws ec2 create-key-pair \ --key-name myvpc-keypair \ --query 'KeyMaterial' \ --output text > myvpc-keypair.pem ## Create user data for a LAMP stack cat < #!/bin/bash sudo yum update -y sudo systemctl enable amazon-ssm-agent sudo systemctl start amazon-ssm-agent sudo systemctl status amazon-ssm-agent EOF ## Create an EC2 instance AWS_EC2_INSTANCE_ID=$(aws ec2 run-instances \ --image-id $AWS_AMI_ID \ --instance-type t2.micro \ --key-name myvpc-keypair \ --monitoring "Enabled=false" \ --security-group-ids $AWS_CUSTOM_SECURITY_GROUP_ID \ --subnet-id $AWS_SUBNET_PUBLIC_ID \ --user-data file://myuserdata.txt \ --private-ip-address 10.0.1.10 \ --query 'Instances[0].InstanceId' \ --output text) ## Create an Instance profile for SSM aws iam create-instance-profile \ --instance-profile-name "AmazonSSMInstanceProfileForInstances" ## Create a trust relation json file cat < { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF ## Create an IAM role for SSM aws iam create-role \ --role-name "AmazonSSMRoleForInstances" \ --assume-role-policy-document file://trust_policy.json ## Attach the required policy for SSM aws iam attach-role-policy \ --role-name "AmazonSSMRoleForInstances" \ --policy-arn "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" ## Add the role to the instance profile aws iam add-role-to-instance-profile \ --instance-profile-name "AmazonSSMInstanceProfileForInstances" \ --role-name "AmazonSSMRoleForInstances" ## Attach the Instance Profile to the EC2 instance aws ec2 associate-iam-instance-profile \ --instance-id "$AWS_EC2_INSTANCE_ID" \ --iam-instance-profile "Name=AmazonSSMInstanceProfileForInstances" ## Add a tag to the ec2 instance aws ec2 create-tags \ --resources $AWS_EC2_INSTANCE_ID \ --tags 'Key=Name,Value=MYAPP' ## Check if instance is added to SSM Managed Instance aws ssm describe-instance-information \ --filters "Key=InstanceIds,Values=$AWS_EC2_INSTANCE_ID" |
Step 2: Create a new SSM state manager association to update SSM agent.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
## --------------------------------------- ## Create an SSM State Manager Association ## --------------------------------------- ## Get current SSM version aws ssm describe-instance-information \ --filters "Key=InstanceIds,Values=$AWS_EC2_INSTANCE_ID" \ --query 'InstanceInformationList[0].AgentVersion' ## Create a new SSM state manager association for SSM agent update AWS_SSM_ASSOCIATION_ID=$(aws ssm create-association \ --targets "Key=tag:Name,Values=MYAPP" \ --name AWS-UpdateSSMAgent \ --schedule-expression "cron(0 0 0 ? * MON *)" \ --association-name "MYASSOCIATION" \ --query 'AssociationDescription.AssociationId' \ --output text) |
Step 3: Get SSM state manager association details.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
## ----------------------------------------- ## Get SSM state manager association details ## ----------------------------------------- ## List all AWS SSM state manager associations aws ssm list-associations ## List all versions of an association for a specific association id aws ssm list-association-versions \ --association-id "$AWS_SSM_ASSOCIATION_ID" ## Get details on the association aws ssm describe-association \ --association-id "$AWS_SSM_ASSOCIATION_ID" ## Get the status of an instance's associations aws ssm describe-instance-associations-status \ --instance-id "$AWS_EC2_INSTANCE_ID" ## Get details of the effective associations for an instance aws ssm describe-effective-instance-associations \ --instance-id "$AWS_EC2_INSTANCE_ID" |
Step 4: Get SSM state manager execution details.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
## --------------------------------------- ## Get SSM state manager execution details ## --------------------------------------- ## Execute an association immediately and only one time ## aws ssm start-associations-once \ ## --association-id "$AWS_SSM_ASSOCIATION_ID" ## not required in our case, as its already executed when we have created the association ## you can use --apply-only-at-cron-interval flag with aws ssm create-association to stop ## immediate execution of the association ## Get details of all executions for the association aws ssm describe-association-executions \ --association-id "$AWS_SSM_ASSOCIATION_ID" ## Get additional details on a specific association execution AWS_SSM_ASSOCIATION_EXE_ID=$(aws ssm describe-association-executions \ --association-id "$AWS_SSM_ASSOCIATION_ID" \ --query 'AssociationExecutions[0].ExecutionId' \ --output text) && aws ssm describe-association-execution-targets \ --association-id "$AWS_SSM_ASSOCIATION_ID" \ --execution-id "$AWS_SSM_ASSOCIATION_EXE_ID" ## Get current SSM version after uodate aws ssm describe-instance-information \ --filters "Key=InstanceIds,Values=$AWS_EC2_INSTANCE_ID" \ --query 'InstanceInformationList[0].AgentVersion' |
Step 5: Cleanup.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
## ------- ## Cleanup ## ------- ## Delete the SSM state manager association aws ssm delete-association \ --association-id "$AWS_SSM_ASSOCIATION_ID" ## Terminate the ec2 instance aws ec2 terminate-instances \ --instance-ids $AWS_EC2_INSTANCE_ID && rm -f myuserdata.txt ## wait for some time sleep 30 ## Delete key pair aws ec2 delete-key-pair \ --key-name myvpc-keypair && rm -f myvpc-keypair.pem ## Delete custom security group aws ec2 delete-security-group \ --group-id $AWS_CUSTOM_SECURITY_GROUP_ID ## Delete internet gateway aws ec2 detach-internet-gateway \ --internet-gateway-id $AWS_INTERNET_GATEWAY_ID \ --vpc-id $AWS_VPC_ID && aws ec2 delete-internet-gateway \ --internet-gateway-id $AWS_INTERNET_GATEWAY_ID ## Delete the custom route table aws ec2 disassociate-route-table \ --association-id $AWS_ROUTE_TABLE_ASSOID && aws ec2 delete-route-table \ --route-table-id $AWS_CUSTOM_ROUTE_TABLE_ID ## Delete the public subnet aws ec2 delete-subnet \ --subnet-id $AWS_SUBNET_PUBLIC_ID ## Delete the vpc aws ec2 delete-vpc \ --vpc-id $AWS_VPC_ID ## Remove the IAM role from Instance Profile aws iam remove-role-from-instance-profile \ --instance-profile-name "AmazonSSMInstanceProfileForInstances" \ --role-name "AmazonSSMRoleForInstances" ## Dettach policy from the role aws iam detach-role-policy \ --role-name "AmazonSSMRoleForInstances" \ --policy-arn "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" ## Delete the IAM role aws iam delete-role \ --role-name "AmazonSSMRoleForInstances" ## Delete the IAM Instance Profile aws iam delete-instance-profile \ --instance-profile-name "AmazonSSMInstanceProfileForInstances" ## Delete the directory created for this demo cd .. && rm -rf ssmdemo |
Hope you have enjoyed this blog post, to get more details on AWS SSM, please refer below AWS documentation
https://docs.aws.amazon.com/systems-manager/index.html