昨天我們很有膽試的將 VPC 砍掉重建,
為的就是將網段重新安排,
但是還沒處理好的部分,
則是 Gitlab 和 Jenkins 目前還連不上,
比較理想的方式是我們建一個 VPC Endpoint 直連 AWS,
但是嘗試了很久在我本機環境建不起來,
所以這個坑只能晚點填,
建議有點規模的公司,
可以考慮建立一個 Site-to-Site VPN,
當作內網的延伸,
這樣 172.31 某個網段以後的都是 aws,
以前的是地端主機,
這樣會更好分辨與管理。
我們沒有要建 VPN,
可是我們還是有連到 Jenkins 和 Gitlab 的需求,
這時候我們可以考慮之前做的 ALB(Application Load Balance),
前幾天我們幫 Portal 建立的 ALB,
其 ALB 和 EC2 套用的 Security Group 是一樣的,
都是收 22、80、443 port,
但是 ALB 只能監聽 80 和 443,
所以即使開了 22 port,
還是只能透過我們綁定的 Elastic IP 去管理主機,
而 ALB 又可以掛載 Web ACLs,
所以整體的安全有保護到,
今天我們 Gitlab 和 Jenkins 也打算使用差不多的方式,
我們建立新的 Security Group,
但是只綁定 Stage VPC 的 CIDR 和我們私人的 IP,
這樣在設定完 DNS 後,
在 Load Balance 就可以根據 IP 白名單來過去,
不在 CIDR 中的就不允許進入。
建立的部分雖然都在 stage/main.tf
但是我們分四個區塊
這裡我們不使用 NLB
係因為 NLB 無法設定 Security Group
也無法綁定 Web ACLs
無法綁定 Web ACLs 問題不大
但是無法鎖定特定 IP 才能存取
就會變成 CI/CD Tools 在網路上裸奔
這不會是我們熱見的
大部分我們的操作都會是連進去點按
比較少會 ssh 進去上 patch
因此這部分我是覺得可以暫時使用 ALB如果真的需要其實可以偷雞一點將 pem key scp 到 portal 或是跳板用的主機等操作完再把 pem key 刪除
一開始我們設定的
stage/main.tf
resource "aws_security_group" "elb_internal" {
name = "elb-internal"
description = "It used for load balance internal."
vpc_id = aws_vpc.stage.id
tags = { Name = "elb-internal" }
revoke_rules_on_delete = null
}
resource "aws_security_group_rule" "elb_internal_igress_80" {
type = "ingress"
from_port = 80
to_port = 80
cidr_blocks = [aws_vpc.stage.cidr_block, var.personal_cidr]
protocol = "tcp"
security_group_id = aws_security_group.elb_internal.id
}
resource "aws_security_group_rule" "elb_internal_igress_443" {
type = "ingress"
from_port = 443
to_port = 443
cidr_blocks = [aws_vpc.stage.cidr_block, var.personal_cidr]
protocol = "tcp"
security_group_id = aws_security_group.elb_internal.id
}
resource "aws_security_group_rule" "elb_internal_egress" {
type = "egress"
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0",]
protocol = "-1"
security_group_id = aws_security_group.elb_internal.id
}
portal 的部分,
target group 是使用 IP 的寫法,
這次我們換換味道,
換成 instance 的寫法。
stage/main.tf
resource "aws_lb" "jenkins" {
name = "jenkins"
internal = false
load_balancer_type = "application"
security_groups = [ aws_security_group.elb_internal.id ]
subnets = data.aws_subnet_ids.public_subnet_ids.ids
enable_deletion_protection = false
tags = {
Creator = "Terraform"
}
}
resource "aws_lb_target_group" "jenkins_tcp_8080" {
name = "jenkins"
port = 80
protocol = "HTTP"
target_type = "instance"
vpc_id = aws_vpc.stage.id
}
resource "aws_lb_target_group_attachment" "jenkins_tcp_8080" {
target_group_arn = aws_lb_target_group.jenkins_tcp_8080.arn
target_id = module.ec2_jenkins.id
port = 8080
}
resource "aws_lb_listener" "jenkins_tcp_80" {
load_balancer_arn = aws_lb.jenkins.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
target_group_arn = aws_lb_target_group.jenkins_tcp_8080.arn
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_listener" "jenkins_tcp_443" {
load_balancer_arn = aws_lb.jenkins.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = aws_acm_certificate.cert.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.jenkins_tcp_8080.arn
}
}
portal 的部分,
target group 是使用 IP 的寫法,
這次我們和 Gitlab 一樣換換味道,
換成 instance 的寫法。
resource "aws_lb_target_group" "gitlab" {
name = "gitlab"
port = 80
protocol = "HTTP"
target_type = "instance"
vpc_id = aws_vpc.stage.id
}
resource "aws_lb_target_group_attachment" "gitlab" {
target_group_arn = aws_lb_target_group.gitlab.arn
target_id = module.ec2_gitlab.id
port = 80
}
resource "aws_lb_listener" "gitlab_80" {
load_balancer_arn = aws_lb.gitlab.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
target_group_arn = aws_lb_target_group.gitlab.arn
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_listener" "gitlab_443" {
load_balancer_arn = aws_lb.gitlab.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = aws_acm_certificate.cert.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.gitlab.arn
}
}
stage/main.tf
resource "aws_wafv2_web_acl_association" "jenkins" {
resource_arn = aws_lb.jenkins.arn
web_acl_arn = aws_wafv2_web_acl.fundamental_acl.arn
}
terraform apply
執行完配置以後
我們登入 AWS Cloud Console
可在 EC2 的負載平衡器看到我們剛剛建立的 ALB
接下來就是要去自己的 DNS Server 設定 CNAME Record
雖然剛剛我有試著遮 Load Balance 的 DNS Host
不過實際上懂技術的人
還是可以知道 DNS Host 和 IP 是什麼
不過即使知道
也會因為 Security Group 擋住而連不上
登入後點按左側選的「管理 Jenkins」
畫面中間的「Jenkins URL」改成自己的網址
之前的教學中
我們的 Jenkinsfile 還沒進版控
這時候我們可以從 Pipeline 進去修改
在 Pipeline 的向下箭頭點按後選擇「組態」
將 Git Repository 的內網 IP 貼上,並儲存
sudo scp -i "/vagrant_data/project/terraform/stage/portal.pem" "/vagrant_data/project/terraform/stage/gitlab.pem" ubuntu@35.73.42.74:/home/ubuntu
當時我們對 portal 只有設定本機電腦
為了要使用 portal 當跳板到 Gitlab 改設定
因此我們需要將 port 22 的 inbound/outbound 做修改
改成 vpc 內的 ip 都可以連
resource "aws_security_group_rule" "ithome_ironman_igress_22" {
type = "ingress"
from_port = 22
to_port = 22
cidr_blocks = [var.personal_cidr, aws_vpc.stage.cidr_block]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_egress_22" {
type = "egress"
from_port = 22
to_port = 22
cidr_blocks = [var.personal_cidr, aws_vpc.stage.cidr_block]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
ssh -i "/vagrant_data/project/terraform/stage/portal.pem" ubuntu@portal的EIP
sudo chmod 400 gitlab.pem
sudo vi /etc/gitlab/gitlab.rb
sudo gitlab-ctl reconfigure
在 gitlab-ctl reconfigure 過程中有出錯是正常的
因為我們 Load Balance 只有鎖內網和個人 IP
因此 let's encryption 在產生憑證的時候就會無法驗證而出錯
在意這問題的人
其實可以先把 security 打開,驗證好之後再關閉
這樣做我們就會得到奇怪的架構
一個是 aws 的自發憑證
另一個則是 load balance 到 EC2 的 Let's Encryption 憑證
sudo gitlab-ctl restart
exit
sudo rm -rf gitlab.pem
exit
因為我們要修改 target group
因此要先將正在監聽中的 80 和 443 port 註解(刪除)
# resource "aws_lb_listener" "gitlab_80" {
# load_balancer_arn = aws_lb.gitlab.arn
# port = "80"
# protocol = "HTTP"
# default_action {
# type = "redirect"
# target_group_arn = aws_lb_target_group.gitlab.arn
# redirect {
# port = "443"
# protocol = "HTTPS"
# status_code = "HTTP_301"
# }
# }
# }
# resource "aws_lb_listener" "gitlab_443" {
# load_balancer_arn = aws_lb.gitlab.arn
# port = "443"
# protocol = "HTTPS"
# ssl_policy = "ELBSecurityPolicy-2016-08"
# certificate_arn = aws_acm_certificate.cert.arn
# default_action {
# type = "forward"
# target_group_arn = aws_lb_target_group.gitlab.arn
# }
# }
原本是 80 port 改成 443 port
resource "aws_lb_target_group" "gitlab" {
name = "gitlab"
port = 443
protocol = "HTTPS"
target_type = "instance"
vpc_id = aws_vpc.stage.id
}
resource "aws_lb_target_group_attachment" "gitlab" {
target_group_arn = aws_lb_target_group.gitlab.arn
target_id = module.ec2_gitlab.id
port = 443
}
terraform apply
這邊需要先註解掉再取消註解
是因為沒有這樣做
會造成 Target Group 有綁定監聽
因此一直無法刪除重建
resource "aws_lb_listener" "gitlab_80" {
load_balancer_arn = aws_lb.gitlab.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
target_group_arn = aws_lb_target_group.gitlab.arn
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_listener" "gitlab_443" {
load_balancer_arn = aws_lb.gitlab.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = aws_acm_certificate.cert.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.gitlab.arn
}
}
因為我們之後要改走內網
所以需要開啟 local network 的設定Admin -> Settings -> Network -> Outbound Requests -> Allow requests to the local network from hooks and services
勾選 Allow requests to the local network from hooks and services
將 Webhook 的 Jenkins URL 改成內網 IP 的 URL
因為我們使用 alb 以後
只剩下 80 和 443 port
因此只能走 https 來 clone repository
畢竟帳號密碼也算是機密資訊
Gitlab 有提供一個不錯的功能
讓我們來建立 Token
使用 Token 的方式來存取
有些環境下會限制 ssh 的存取
這時候走 https 的話
使用 token 的方式來存取是相對安全的做法
在專案中的 Settings,可選取 Access_Token 建立 Token
git remote set-url origin https://使用者名稱:TOKEN@gitlab.markmewmew.com/ithome-ironman-2021/portal.git
git fetch origin
CodeDeploy 如果莫名失敗的,請參考這篇,需要建立一個新的 IAM Role,然後原本 EC2 綁定的解綁,綁定新的沒權限的,再解綁然後綁定回原來的。
大方向來說,
架構調整會先在這裡告一段落,
這裡先說聲抱歉,
能力上的不足,
本來想把 VPN 環境建置起來,
這樣就可以順利連到 VPC 直接順取內網資源。
或是在 Route53 中建立自訂託管區域,
這樣會因為 DHCP 的設定,
而解析到 host,
讓我們服務在內部溝通時,
可以不用綁 EC2 或是 IP 綁很死,
但是無奈遇到一些技術上的問題就暫時作罷。
明天我會中場休息做個閒聊,
接下來我們的步驟會有些不同,
繼續進行改造,
將我們的服務打包成 Docker,
並使用 AWS 的 Kubernetes 服務(EKS)管理,
接著搭配新的部署工具 Octopus Deploy
部署到 EKS 上。