Skip to content

Commit 81eb8f0

Browse files
committed
Update GitHub Action deploys to use SSH instead of AWS SSM Commands, because they don't work.
AWS SSM Commands are unable to return error codes, so the GitHub command always reports success, even when the deploys fail.
1 parent c442ab4 commit 81eb8f0

File tree

3 files changed

+74
-143
lines changed

3 files changed

+74
-143
lines changed

.env.example

+1
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,4 @@ VITE_APP_NAME="${APP_NAME}"
6565

6666
OS_USER=ec2-user
6767
OS_UID=1000
68+
OS_GROUP_ID=1000

.github/workflows/deploy.yml

+32-33
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
name: Deploy to EC2
2-
32
on:
4-
push:
5-
branches:
6-
- main
7-
3+
push:
4+
branches:
5+
- main
86
jobs:
9-
start:
10-
runs-on: ubuntu-latest
11-
12-
steps:
13-
- uses: actions/checkout@v2
7+
deploy:
8+
runs-on: ubuntu-latest
149

15-
- name: AWS SSM Send-Command
16-
uses: peterkimzz/aws-ssm-send-command@master
17-
id: ssm
18-
with:
19-
aws-region: ${{ secrets.AWS_REGION }}
20-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
21-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
22-
instance-ids: ${{ secrets.INSTANCE_ID }}
10+
steps:
11+
- name: Install SSH key
12+
uses: shimataro/ssh-key-action@v2
13+
with:
14+
key: ${{ secrets.AWS_INSTANCE_SSH_PRIVATE_KEY }}
15+
known_hosts: ${{ secrets.KNOWN_HOSTS }}
2316

24-
working-directory: /home/ec2-user
25-
command: |
26-
sudo mkdir -p /opt/albertclo.com
27-
cd /opt/albertclo.com
28-
sudo chown -R ec2-user:ec2-user .
29-
if [ ! -d .git ]; then
30-
git clone https://github.com/AlbertClo/albertclo.com .
31-
fi
32-
git reset HEAD --hard
33-
git checkout main
34-
git fetch origin
35-
git reset --hard origin/main
36-
docker-compose --env-file .env -f infra/docker/docker-compose.yml exec php php artisan migrate
37-
docker-compose --env-file .env -f infra/docker/docker-compose.yml exec php composer install
38-
docker-compose --env-file .env -f infra/docker/docker-compose.yml exec node npm run build
17+
- name: Deploy to EC2
18+
env:
19+
HOST: ec2-user@${{ secrets.AWS_INSTANCE_IP }}
20+
run: |
21+
ssh -i StrictHostKeyChecking=accept-new ec2-user@${{ secrets.AWS_INSTANCE_IP }} "
22+
set -e
23+
sudo mkdir -p /opt/albertclo.com
24+
sudo chown -R ec2-user:ec2-user /opt/albertclo.com
25+
cd /opt/albertclo.com
26+
if [ ! -d .git ]; then git clone https://github.com/AlbertClo/albertclo.com.git . ; fi
27+
git config --global --add safe.directory /opt/albertclo.com
28+
git remote set-url origin https://github.com/AlbertClo/albertclo.com.git
29+
git add -A
30+
git reset HEAD --hard
31+
git checkout main
32+
git fetch origin
33+
git reset --hard origin/main
34+
docker-compose --env-file .env -f infra/docker/docker-compose.yml up -d
35+
docker-compose --env-file .env -f infra/docker/docker-compose.yml exec php composer install
36+
docker-compose --env-file .env -f infra/docker/docker-compose.yml exec php php artisan migrate
37+
echo 'done'"

infra/terraform/main.tf

+41-110
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,6 @@ resource "aws_subnet" "albertclo_subnet" {
6868
})
6969
}
7070

71-
# Creates an SSH key pair for accessing EC2 instances
72-
resource "aws_key_pair" "albert_ssh_key" {
73-
key_name = "albert_ssh_key"
74-
public_key = file("public_keys/albert_id_rsa.pub")
75-
76-
tags = merge(local.common_tags, {
77-
Name = "albert_ssh_key"
78-
})
79-
}
80-
8171
# Generates an IAM user and access key for GitHub Actions
8272
resource "aws_iam_user" "albertclo_github_actions_user" {
8373
name = "albertclo-github-actions"
@@ -151,12 +141,14 @@ resource "aws_security_group" "albertclo_com_sec_group" {
151141
cidr_blocks = ["0.0.0.0/0"]
152142
}
153143

144+
# We need ssh access from the GitHub Actions runner, so we can't limit the IP address ranges easily.
145+
# todo: Install and configure fail2ban. Change ssh port to a non-standard port. Use SSH key authentication only (no password authentication)
154146
ingress {
155-
description = "SSH from personal IPs"
147+
description = "SSH access IPs"
156148
from_port = 22
157149
to_port = 22
158150
protocol = "tcp"
159-
cidr_blocks = ["197.245.68.172/32"]
151+
cidr_blocks = ["0.0.0.0/0"]
160152
}
161153

162154
egress {
@@ -179,6 +171,32 @@ data "aws_ssm_parameter" "amzn2_ami" {
179171
# Retrieves information about the current AWS region
180172
data "aws_region" "current" {}
181173

174+
# Albert's SSH public key for accessing EC2 instances
175+
resource "aws_key_pair" "albert_ssh_key" {
176+
key_name = "albert_ssh_key"
177+
public_key = file("public_keys/albert_id_rsa.pub")
178+
179+
tags = merge(local.common_tags, {
180+
Name = "albert_ssh_key"
181+
})
182+
}
183+
184+
# This private key will be added on the GitHub repo so that the GitHub action can use it to ssh into the EC2 instance
185+
resource "tls_private_key" "github_action_ssh_key" {
186+
algorithm = "RSA"
187+
rsa_bits = 4096
188+
}
189+
190+
# Create a new AWS key pair using the public key
191+
resource "aws_key_pair" "github_action_ssh_key" {
192+
key_name = "github_action_ssh_key"
193+
public_key = tls_private_key.github_action_ssh_key.public_key_openssh
194+
195+
tags = merge(local.common_tags, {
196+
Name = "github_action_ssh_key"
197+
})
198+
}
199+
182200
# Creates an EC2 instance for hosting albertclo.com
183201
resource "aws_instance" "albertclo_com" {
184202
ami = data.aws_ssm_parameter.amzn2_ami.value
@@ -200,11 +218,12 @@ resource "aws_instance" "albertclo_com" {
200218
})
201219
}
202220

203-
iam_instance_profile = aws_iam_instance_profile.albert_clo_ec2_profile.name
204-
205221
user_data = <<-EOF
206222
#!/bin/bash
207223
224+
# Add the new public key to authorized_keys
225+
echo "${tls_private_key.github_action_ssh_key.public_key_openssh}" >> /home/ec2-user/.ssh/authorized_keys
226+
208227
# Install required software
209228
sudo yum update -y
210229
sudo yum install -y docker
@@ -291,91 +310,6 @@ resource "aws_ssm_parameter" "albertclo_github_deploy_key" {
291310
})
292311
}
293312

294-
variable "github_repo" {
295-
description = "GitHub repository in the format owner/repo"
296-
type = string
297-
default = "AlbertClo/albertclo.com"
298-
}
299-
300-
# Creates an IAM role for GitHub Actions to assume for deployments
301-
resource "aws_iam_role" "albertclo_github_actions_role" {
302-
name = "albertclo-github-actions-deploy-role"
303-
304-
assume_role_policy = jsonencode({
305-
Version = "2012-10-17"
306-
Statement = [
307-
{
308-
Action = "sts:AssumeRole"
309-
Effect = "Allow"
310-
Principal = {
311-
Federated = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/token.actions.githubusercontent.com"
312-
}
313-
Condition = {
314-
StringLike = {
315-
"token.actions.githubusercontent.com:sub" : "repo:${var.github_repo}:*"
316-
}
317-
}
318-
}
319-
]
320-
})
321-
}
322-
323-
# Attaches a policy to the GitHub Actions role to allow deployments
324-
resource "aws_iam_role_policy" "albertclo_github_actions_policy" {
325-
name = "albertclo-github-actions-deploy-policy"
326-
role = aws_iam_role.albertclo_github_actions_role.id
327-
328-
policy = jsonencode({
329-
"Version" : "2012-10-17",
330-
"Statement" : [
331-
{
332-
"Action" : [
333-
"ec2:DescribeInstances",
334-
"ec2:DescribeRegions",
335-
"sts:GetCallerIdentity",
336-
"sts:AssumeRole"
337-
],
338-
"Effect" : "Allow",
339-
"Resource" : "*"
340-
},
341-
{
342-
"Action" : [
343-
"ssm:SendCommand"
344-
],
345-
"Condition" : {
346-
"StringLike" : {
347-
"ssm:ResourceTag/Name" : "albertclo.com"
348-
}
349-
},
350-
"Effect" : "Allow",
351-
Resource = [
352-
"arn:aws:ec2:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:instance/*"
353-
]
354-
},
355-
{
356-
"Action" : [
357-
"ssm:SendCommand"
358-
],
359-
"Effect" : "Allow",
360-
"Resource" : [
361-
"arn:aws:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:document/AWS-RunShellScript"
362-
]
363-
}
364-
]
365-
})
366-
}
367-
368-
# Attaches the SSM Managed Instance Core policy to the EC2 role
369-
resource "aws_iam_role_policy_attachment" "ssm_policy" {
370-
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
371-
role = aws_iam_role.albert_clo_ec2_ssm_role.name
372-
}
373-
374-
# Outputs the ARN of the GitHub Actions role
375-
output "albertclo_github_actions_role_arn" {
376-
value = aws_iam_role.albertclo_github_actions_role.arn
377-
}
378-
379313
# Outputs the public IP address of the EC2 instance
380314
output "instance_public_ip" {
381315
description = "Public IP address of the EC2 instance"
@@ -394,17 +328,14 @@ output "github_public_key" {
394328
value = tls_private_key.albertclo_github_deploy_key.public_key_openssh
395329
}
396330

397-
# Outputs the access key for GitHub Actions
398-
output "github_actions_access_key" {
399-
description = "Access key for GitHub Actions"
400-
value = aws_iam_access_key.albertclo_github_actions_access_key.id
331+
# Outputs the private key for GitHub Actions
332+
# This output is sensitive. To view this output, run `terraform output github_action_ssh_private_key`
333+
output "github_action_ssh_private_key" {
334+
value = tls_private_key.github_action_ssh_key.private_key_pem
335+
sensitive = true
401336
}
402337

403-
# Outputs the secret key for GitHub Actions
404-
# This output is sensitive. To view this output, run `terraform output github_actions_secret_key`
405-
output "github_actions_secret_key" {
406-
description = "Secret key for GitHub Actions"
407-
value = aws_iam_access_key.albertclo_github_actions_access_key.secret
408-
sensitive = true
338+
# Output the public key
339+
output "github_action_ssh_public_key" {
340+
value = tls_private_key.github_action_ssh_key.public_key_openssh
409341
}
410-

0 commit comments

Comments
 (0)