iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
DevOps

關於我幫新公司建立整套部屬流程那檔事系列 第 11

EP11 - 為你的 portal 添加 Load Balance 和掛載 Web ACLs

Elastic Load Balancing

什麼是 Elastic Load Balancing

Elastic Load Balancing 可在多個目標 (例如 Amazon EC2 執行個體、容器、IP 地址、Lambda 函數和虛擬設備) 之間自動分配傳入的應用程式流量。
它可以在單一可用區域或跨多個可用區域處理您應用程式流量的各種負載。
Elastic Load Balancing 提供四種負載平衡器,
它們都具有下列特性:高可用性、自動擴展,以及讓您的應用程式具備容錯功能的強大安全防護。

與傳統的 Load Balance 不同的是
以往在做 Load Balance 的時候都是需要建立一台主機
但使用 AWS 的 Elastic Load Balancing
我們就不用另外建一台 EC2
然後再另外安裝 Nginx 了

Elastic Load Balancing 有哪些

AWS 提供的 Elastic Load Balancing 有四種
「Application Load Balancer」、「Network Load Balancer」、「Gateway Load Balancer」、「Classic Load Balancer」共四種

Application Load Balancer(ALB)只對外開 80 和 443 port
屬於 OSI 七層中的第七層應用層的部分
支援 AWS 的 IP、EC2 和 Lambda

Network Load Balancer(NLB)則是屬於第四層
支援 IP、EC2 兩種服務
如果要處理 80、443 以外的 port
就只能夠使用 NLB 來做附載平衡
除了 IP 和 port 以外
也支援 TCP 和 UDP
這在設定上時需要特別注意
傳統我們在使用的 Nginx 比較是 NLB

Gateway Load Balancer(GLB)
則是屬於 Layer 3 + Layer 4 的負載平衡
只能套用在 IP 上
實際上我沒有用過它
也沒辦法多做解釋

Classic Load Balancer(CLB)就是傳統的 Load Balance
有多傳統?其實不重要
2022 年 August 15 之後就不能用了
也不要花太多時間了解
了解完了明年還是要翻掉

看可以應用在 AWS 範圍的多少
很明顯可以看得出來
AWS 比較希望我們用 ALB 就好了
其他的非必要就別用了
再加上 ALB 可以掛載 AWS WAF 的 Web ACLs
讓你連線時還可以檢查是否有惡意攻擊
這當然也是我們要應用的部分

Terraform 建置 load balance

用 IaC 的方式來建置 load balance
最基礎的需要設定四個
load balance 本身、目標群組以及把兩者綁定
然後是設定 80 和 443 port

上面我們有提到
我們是使用 alb
因此只能夠設定 80 和 443
最多也只會有五個區塊

安全群組我們先沿用 portal 的 security group

main.tf

resource "aws_lb" "portal" {
    name               = "ithome-ironman-portal"
    internal           = false
    load_balancer_type = "application"
    security_groups    = [ aws_security_group.ithome_ironman_portal.id ]
    subnets            = data.aws_subnet_ids.subnet_ids.ids
    
    enable_deletion_protection = false
    
    tags = {
        Creator = "Terraform"
    }
}

resource "aws_lb_target_group" "portal" {
    name        = "ithome-ironman-portal"
    port        = 80
    protocol    = "HTTP"
    target_type = "ip"
    vpc_id      = data.aws_vpc.default.id

    stickiness {
        type = "lb_cookie"
    }
}

resource "aws_lb_target_group_attachment" "portal01" {
    target_group_arn = aws_lb_target_group.portal.arn
    target_id        = aws_instance.ithome_ironman_portla.private_ip
}

resource "aws_lb_listener" "portal_port80" {
    load_balancer_arn = aws_lb.portal.arn
    port              = "80"
    protocol          = "HTTP"
    
    default_action {
        type             = "forward"
        target_group_arn = aws_lb_target_group.portal.arn
    }
}
terraform apply

建置好後
可以登入 aws cloud console 看到建置好的 load balance
https://ithelp.ithome.com.tw/upload/images/20210923/20141518l7nGshzLZV.png

直接輸入 DNS 卻會出現 504 的錯誤
這是因為我們的 inbound 只開電腦的 ip
但是現在連到 ec2 的是 load balance 的 ip
所以還需要跳整 inbound/outbound 的設定
https://ithelp.ithome.com.tw/upload/images/20210923/20141518nTG3JBm0S3.png

修改 portal 的 inbound 和 outbound

load balance 的 ip 是浮動的
portal 如果是抓當下的 ip
過幾個月 ip 改變後就要再次修改
所以我這次的修改我們還需要修改一下 inbound

之前我們是設定 var.personal_cidr
現在要改成 0.0.0.0/0

resource "aws_security_group_rule" "ithome_ironman_igress_80" {
    type              = "ingress"
    from_port         = 80
    to_port           = 80
    cidr_blocks       = ["0.0.0.0/0",]
    protocol          = "tcp"
    security_group_id = aws_security_group.ithome_ironman_portal.id
}

resource "aws_security_group_rule" "ithome_ironman_igress_443" {
    type              = "ingress"
    from_port         = 443
    to_port           = 443
    cidr_blocks       = ["0.0.0.0/0",]
    protocol          = "tcp"
    security_group_id = aws_security_group.ithome_ironman_portal.id
}
terraform apply

執行配置後
打開網頁就可以看到 ALLOWED_HOSTS 的錯誤訊息
這時候我們只要把 Load Balance 的 Host 加上去即可
push code 還可以順便測試昨天建好的 CI/CD
https://ithelp.ithome.com.tw/upload/images/20210923/201415181bhzL2oShG.png

匯入憑證後的修改

目前我手邊沒有可用的 DNS 和 憑證可供參考
因此下列的程式碼不保證可以用

在 UI 介面中填寫憑證相關資訊後
Terraform 就可以透過 data 將匯入的憑證找出來
添加一個 listener,綁定憑證監聽 443 port
原本 80 port 的則強制轉導到 443 port

data "aws_acm_certificate" "dns_host" {
    domain = "*.你的網域"
    status = ["ISSUED"]
}

resource "aws_lb_listener" "portal_portal443" {
    load_balancer_arn = aws_lb.portal.arn
    port              = "443"
    protocol          = "HTTPS"
    ssl_policy        = "ELBSecurityPolicy-2016-08"
    certificate_arn   = data.aws_acm_certificate.dns_host.arn
  
    default_action {
        type             = "forward"
        target_group_arn = aws_lb_target_group.portal.arn
    }
}

resource "aws_lb_listener" "portal_port80" {
    load_balancer_arn = aws_lb.portal.arn
    port              = "80"
    protocol          = "HTTP"
    
    default_action {
        type             = "redirect"
        target_group_arn = aws_lb_target_group.portal.arn
      
        redirect {
            port        = "443"
            protocol    = "HTTPS"
            status_code = "HTTP_301"
        }
    }
}

AWS WAF

什麼是 AWS WAF

AWS WAF是一種 Web 應用程式防火牆
可讓您監控轉送至 Amazon CloudFront 分發、Amazon API Gateway REST API、Application Load Balancer 或的 HTTP(S) 請求

Web ACLs

Web 存取控制清單(Web ACL)可讓您詳細控制受保護資源回應的所有 HTTP(S) Web 請求。

您可以保護 Amazon CloudFront、Amazon API Gateway、Application Load Balancer 和AWS AppSync的費用。

每個區域最多可產生 100 個 Web ACL
而每個 Web ACL 最多可訂到 最大 1500 Web ACL 容量單位 (WCU)
至於 WCU 就有點謎了
根據你的規則來訂
像是 1 個 IP 就是 1 個 WCU
通常用 IP 都是鎖白名單或是黑名單
至於其他規則,像是 SQL Inject、Cross Site Scripting 各自的 WCU 都不同
總計上限就是 1500

使用上是非常夠用了
一條 Web ACLs 可以綁定多個 ALB
如果超過 1500 就多制定一條
能夠制定到 150000 單位其實公司也是有一定規模

AWS Shield

AWS 針對 DDoS 攻擊提供 AWS Shield Standard 和 AWS Shield Advanced 保護。

AWS Shield Standard 已自動包含在內
對於您已支付 AWS WAF 和其他 AWS 服務的費用
此無需額外費用

如果覺得基礎不夠使用
對於額外的 DDoS 攻擊保護
有提供 AWSRouteAWS Shield Advanced
可為 AWS 的資源提供擴充的 DDoS 攻擊防護。

既然基礎已經有了
我們就只會使用 Web ACLs 就好了

Terraform 建置 WebACLs

WebACLs 的建置就真的比較無腦
是使用 AWS 做好的 AWSManagedRulesCommonRuleSet
至於裏面包含什麼呢?
有興趣的可以自己參考官方文件
從 URI 到檔案名稱的讀寫
大致上就是該擋的都幫你做了
不確定要加哪些 ACL 的話
建議預設就用這個

去 terraform 查找寫法時
記得要找 aws_wafv2
不然會找到舊版 waf 的寫法

resource "aws_wafv2_web_acl" "fundamental_acl" {
    name  = "fundamental-acl"
    scope = "REGIONAL"
    
    default_action {
        allow {}
    }

    rule {
        name     = "aws-managed-common-rule"
        priority = 1
        
        override_action {
            count {}
        }
        
        statement {
            # aws support suggests to use this to protect the common attach
            managed_rule_group_statement {
                name        = "AWSManagedRulesCommonRuleSet"
                vendor_name = "AWS"
            }
        }

        visibility_config {
            cloudwatch_metrics_enabled = false
            metric_name                = "aws-managed-common-rule"
            sampled_requests_enabled   = false
        }
    }
    
    tags = {
        Creator = "Terraform"
    }
    
    visibility_config {
        cloudwatch_metrics_enabled = false
        metric_name                = "fundamental-acl"
        sampled_requests_enabled   = false
    }
}
terraform apply

建立完成後登入 aws cloud console
就可以看到我們建立的成果
https://ithelp.ithome.com.tw/upload/images/20210923/201415186tQEpAlWgo.png

https://ithelp.ithome.com.tw/upload/images/20210923/20141518r688vzLo6y.png

上面我們有提到每個 Web ACL 最多可訂到 最大 1500 Web ACL 容量單位 (WCU)
我們用了一條 AWS 的規則就佔了 700
其實使用起來還是綽綽有餘

https://ithelp.ithome.com.tw/upload/images/20210923/201415183WVeStprTy.png

WebACLs 關聯 ALB

再多建立一個關聯
把 web acls 和 load balance 接起來
這樣就算是配置完成囉

resource "aws_wafv2_web_acl_association" "portal" {
    resource_arn = aws_lb.portal.arn
    web_acl_arn  = aws_wafv2_web_acl.fundamental_acl.arn
}

完成後可以在 aws cloud console 的 Associated AWS resources 中
看到我們的 alb 已經套用上去了

https://ithelp.ithome.com.tw/upload/images/20210923/201415180QeINqqzSm.png

參考資料:

  1. Elastic Load Balancing
  2. Elastic Load Balancing 功能
  3. AWS WAF 配額
  4. AWS受管理規則規則群組清單
  5. aws_wafv2_web_acl
  6. aws_wafv2_web_acl_association

上一篇
EP10 - Django 持續整合持續部署使用 Jenkins 和 AWS CodeDeploy
下一篇
EP12 - 重構並模組化 Terraform 程式碼
系列文
關於我幫新公司建立整套部屬流程那檔事30

尚未有邦友留言

立即登入留言