Deploying DevOps App to EC2 via SSM using GitHub Actions
Table of contents:
Initial Setup
Issues Encountered
Final GitHub Actions Workflow
Secrets Used in GitHub
Summary of Fixes
Initial Setup
Objective: Automate deployment of your app from GitHub to an EC2 instance via AWS SSM (no SSH key needed, zero-open-ports).
Environment: AWS Free Tier, EC2 t3.micro, Amazon Linux.
Tools: GitHub Actions, AWS Systems Manager (SSM), EC2, IAM roles and policies.
Issues Encountered
Git & Tagging Issues
git tag v1.0.0
git push origin v1.0.0
fatal: tag 'v1.0.0' already exists
Cause: Tag already exists locally or on GitHub.
Fix: Use a new tag number (
v1.0.2,v1.0.4) and push:
git tag -f v1.0.2 # force update if needed
git push origin v1.0.2
SSH-based Deployment Issues
Initially tried using SSH with private key.
Errors included:
dial tcp ***:22: i/o timeout
Cause: Security group rules were blocking access, had to restrict inbound to your IP.
Pain point: Maintaining SSH keys and updating them in GitHub secrets is brittle.
✅ Lesson: Using SSM avoids opening port 22 entirely, more secure and reliable.
SSM Managed Nodes
- SSM Agent installed on EC2:
sudo systemctl status amazon-ssm-agent
Initially, nodes were not appearing as managed instances in Fleet Manager.
Error in CLI:
aws ssm describe-instance-information
An error occurred (AccessDeniedException)
- Cause: EC2 IAM role
EC2-SSM-Deploy-Rolelacked proper SSM permissions.
IAM Role and Policy Issues
The IAM role attached:
EC2-SSM-Deploy-RoleInitial policies:
AmazonSSMManagedInstanceCore(AWS managed)
Missing: Permission for ssm:DescribeInstanceInformation and SSM commands.
- Fix:
Created a custom policy
SSMManagedInstanceCoreCustom.Attached it to
EC2-SSM-Deploy-Role.
- Result: EC2 became a managed instance in
Fleet Manager, Online status verified.
GitHub Actions Workflow Errors
- Wrong AWS CLI action:
Error: Unable to resolve action aws-actions/aws-cli
Error: Unable to resolve action amazon-actions/aws-cli
- Cause: No such repository exists; GitHub Actions cannot find it.
✅ Fix: Use aws-actions/configure-aws-credentials@v3 for credentials and run AWS CLI commands in run:.
Final GitHub Actions Workflow
File: .github/workflows/deploy.yml
name: Deploy to EC2 via SSM
on:
push:
tags:
- "v*.*"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Deploy via AWS SSM
run: |
aws ssm send-command \
--targets "Key=InstanceIds,Values=i-068ca0d3a5b74206a" \
--document-name "AWS-RunShellScript" \
--comment "Deploy DevOps app" \
--parameters '{"commands":["cd /usr/share/nginx/html/DevOps","git pull origin main","sudo systemctl reload nginx"]}' \
--output text
Explanation:
Trigger: Runs on tag pushes (vX.X.X).
Checkout: Pulls repo code into GitHub Actions runner.
AWS Credentials: Uses GitHub secrets to authenticate via AWS CLI.
- Secrets used:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION.
- Deployment via SSM:
-
ssm send-commandruns shell commands on the EC2 instance without SSH.- Commands:
- Change directory:
/usr/share/nginx/html/DevOps - Pull latest code:
git pull origin main - Reload Nginx:
sudo systemctl reload nginx - Output set to
textfor readability in Actions logs.
Secrets Used in GitHub
| Name | Value |
|---|---|
AWS_ACCESS_KEY_ID |
From IAM user alok-admin
|
AWS_SECRET_ACCESS_KEY |
From IAM user alok-admin
|
AWS_REGION |
us-east-1 (example) |
EC2_HOST |
EC2 Public IP |
EC2_SSH_KEY |
Not used in final SSM workflow |
✅ No need to open SSH ports now; deployment works via SSM.
Summary of Fixes
| Problem | Fix |
|---|---|
| Git tag already exists | Increment tag version, push |
| SSH deployment failing | Moved to SSM, no open ports needed |
| EC2 not a managed node | Installed SSM agent, attached IAM role |
| IAM role missing SSM permissions | Added AmazonSSMManagedInstanceCore + custom policy |
| Workflow action not found | Replaced with aws-actions/configure-aws-credentials@v3 + CLI run |
| AccessDeniedException from AWS CLI | Fixed IAM policies attached to role |
✅ Outcome
EC2 shows as managed node in Fleet Manager.
GitHub Actions workflow triggers on tag push, connects via SSM, pulls latest code, reloads Nginx.
Fully automated, zero-open-ports deployment.
Works on Free Tier, minimal IAM setup, no SSH maintenance.
Top comments (0)