×

AWS WAF 是一种 Web 应用防火墙,允许您监控转发到受保护的 Web 应用程序资源的 HTTP 和 HTTPS 请求。

您可以使用 AWS 应用负载均衡器 (ALB) 向您的 AWS 上的 Red Hat OpenShift 服务 (ROSA) 工作负载添加 Web 应用防火墙 (WAF)。使用外部解决方案可以保护 ROSA 资源免受因处理 WAF 而导致的服务拒绝攻击。

建议您使用更灵活的CloudFront 方法,除非您绝对必须使用基于 ALB 的解决方案。

先决条件

  • 多可用区 (AZ) ROSA(HCP 或 Classic)集群。

    根据AWS 文档,AWS ALB 至少需要跨 AZ 的两个*公共*子网。因此,只有多 AZ ROSA 集群才能与 ALB 一起使用。

  • 您可以访问 OpenShift CLI(oc)。

  • 您可以访问 AWS CLI(aws)。

环境设置

  • 准备环境变量

    $ export AWS_PAGER=""
    $ export CLUSTER=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}")
    $ export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
    $ export OIDC_ENDPOINT=$(oc get authentication.config.openshift.io cluster -o jsonpath='{.spec.serviceAccountIssuer}' | sed  's|^https://||')
    $ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    $ export SCRATCH="/tmp/${CLUSTER}/alb-waf"
    $ mkdir -p ${SCRATCH}
    $ echo "Cluster: $(echo ${CLUSTER} | sed 's/-[a-z0-9]\{5\}$//'), Region: ${REGION}, OIDC Endpoint: ${OIDC_ENDPOINT}, AWS Account ID: ${AWS_ACCOUNT_ID}"

AWS VPC 和子网

此部分仅适用于部署到现有 VPC 的集群。如果您没有将集群部署到现有 VPC,请跳过此部分,继续执行下面的安装部分。

  1. 将以下变量设置为 ROSA 部署的正确值

    $ export VPC_ID=<vpc-id> (1)
    $ export PUBLIC_SUBNET_IDS=(<space-separated-list-of-ids>) (2)
    $ export PRIVATE_SUBNET_IDS=(<space-separated-list-of-ids>) (3)
    1 替换为集群的 VPC ID,例如:export VPC_ID=vpc-04c429b7dbc4680ba
    2 替换为集群的私有子网 ID 的空格分隔列表,确保保留()。例如:export PUBLIC_SUBNET_IDS=(subnet-056fd6861ad332ba2 subnet-08ce3b4ec753fe74c subnet-071aa28228664972f)
    3 替换为集群的私有子网 ID 的空格分隔列表,确保保留()。例如:export PRIVATE_SUBNET_IDS=(subnet-0b933d72a8d72c36a subnet-0817eb72070f1d3c2 subnet-0806e64159b66665a)
  2. 使用集群标识符向集群的 VPC 添加标签

    $ aws ec2 create-tags --resources ${VPC_ID} \
      --tags Key=kubernetes.io/cluster/${CLUSTER},Value=shared --region ${REGION}
  3. 向您的公共子网添加标签

    $ aws ec2 create-tags \
      --resources ${PUBLIC_SUBNET_IDS} \
      --tags Key=kubernetes.io/role/elb,Value='1' \
            Key=kubernetes.io/cluster/${CLUSTER},Value=shared \
      --region ${REGION}
  4. 向您的私有子网添加标签

    $ aws ec2 create-tags \
      --resources ${PRIVATE_SUBNET_IDS} \
      --tags Key=kubernetes.io/role/internal-elb,Value='1' \
            Key=kubernetes.io/cluster/${CLUSTER},Value=shared \
      --region ${REGION}

部署 AWS Load Balancer Operator

AWS Load Balancer Operator 用于在 ROSA 集群中安装、管理和配置aws-load-balancer-controller 的实例。要在 ROSA 中部署 ALB,我们首先需要部署 AWS Load Balancer Operator。

  1. 通过运行以下命令创建一个新项目来部署 AWS Load Balancer Operator

    $ oc new-project aws-load-balancer-operator
  2. 如果 AWS Load Balancer Controller 还没有策略,则创建一个新的 AWS IAM 策略,运行以下命令

    该策略来自上游 AWS Load Balancer Controller 策略。这是操作员运行所必需的。

    $ POLICY_ARN=$(aws iam list-policies --query \
         "Policies[?PolicyName=='aws-load-balancer-operator-policy'].{ARN:Arn}" \
         --output text)
    $ if [[ -z "${POLICY_ARN}" ]]; then
        wget -O "${SCRATCH}/load-balancer-operator-policy.json" \
           https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json
         POLICY_ARN=$(aws --region "$REGION" --query Policy.Arn \
         --output text iam create-policy \
         --policy-name aws-load-balancer-operator-policy \
         --policy-document "file://${SCRATCH}/load-balancer-operator-policy.json")
    fi
  3. 为 AWS Load Balancer Operator 创建 AWS IAM 信任策略

    $ cat <<EOF > "${SCRATCH}/trust-policy.json"
    {
     "Version": "2012-10-17",
     "Statement": [
     {
     "Effect": "Allow",
     "Condition": {
       "StringEquals" : {
         "${OIDC_ENDPOINT}:sub": ["system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-operator-controller-manager", "system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-controller-cluster"]
       }
     },
     "Principal": {
       "Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/${OIDC_ENDPOINT}"
     },
     "Action": "sts:AssumeRoleWithWebIdentity"
     }
     ]
    }
    EOF
  4. 为 AWS Load Balancer Operator 创建 AWS IAM 角色

    $ ROLE_ARN=$(aws iam create-role --role-name "${CLUSTER}-alb-operator" \
       --assume-role-policy-document "file://${SCRATCH}/trust-policy.json" \
       --query Role.Arn --output text)
  5. 通过运行以下命令将 AWS Load Balancer Operator 策略附加到我们之前创建的 IAM 角色

    $ aws iam attach-role-policy --role-name "${CLUSTER}-alb-operator" \
         --policy-arn ${POLICY_ARN}
  6. 为 AWS Load Balancer Operator 创建一个密钥,以承担我们新创建的 AWS IAM 角色

    $ cat << EOF | oc apply -f -
    apiVersion: v1
    kind: Secret
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    stringData:
      credentials: |
        [default]
        role_arn = ${ROLE_ARN}
        web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
    EOF
  7. 安装 AWS Load Balancer Operator

    $ cat << EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    spec:
      upgradeStrategy: Default
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    spec:
      channel: stable-v1.0
      installPlanApproval: Automatic
      name: aws-load-balancer-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
      startingCSV: aws-load-balancer-operator.v1.0.0
    EOF
  8. 使用 operator 部署 AWS Load Balancer Controller 的实例

    如果您在此处收到错误,请等待一分钟后再试,这意味着 Operator 尚未完成安装。

    $ cat << EOF | oc apply -f -
    apiVersion: networking.olm.openshift.io/v1
    kind: AWSLoadBalancerController
    metadata:
      name: cluster
    spec:
      credentials:
        name: aws-load-balancer-operator
      enabledAddons:
        - AWSWAFv2
    EOF
  9. 检查 operator 和 controller pod 是否都在运行

    $ oc -n aws-load-balancer-operator get pods

    您应该看到以下内容,如果没有,请稍候片刻然后重试

    NAME                                                             READY   STATUS    RESTARTS   AGE
    aws-load-balancer-controller-cluster-6ddf658785-pdp5d            1/1     Running   0          99s
    aws-load-balancer-operator-controller-manager-577d9ffcb9-w6zqn   2/2     Running   0          2m4s

部署示例应用程序

  1. 为我们的示例应用程序创建一个新项目

    $ oc new-project hello-world
  2. 部署一个 hello world 应用程序

    $ oc new-app -n hello-world --image=docker.io/openshift/hello-openshift
  3. 将预先创建的服务资源转换为 NodePort 服务类型

    $ oc -n hello-world patch service hello-openshift -p '{"spec":{"type":"NodePort"}}'
  4. 使用 AWS Load Balancer Operator 部署 AWS ALB

    $ cat << EOF | oc apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-openshift-alb
      namespace: hello-world
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
    spec:
      ingressClassName: alb
      rules:
        - http:
            paths:
              - path: /
                pathType: Exact
                backend:
                  service:
                    name: hello-openshift
                    port:
                      number: 8080
    EOF
  5. Curl AWS ALB Ingress 端点以验证 hello world 应用程序是否可访问

    AWS ALB 配置需要几分钟时间。如果您收到显示curl: (6) Could not resolve host的错误,请稍候片刻然后重试。

    $ INGRESS=$(oc -n hello-world get ingress hello-openshift-alb -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    $ curl "http://${INGRESS}"
    示例输出
    Hello OpenShift!

配置 AWS WAF

AWS WAF 服务是一种 Web 应用防火墙,允许您监控、保护和控制转发到受保护的 Web 应用程序资源(如 ROSA)的 HTTP 和 HTTPS 请求。

  1. 创建一个 AWS WAF 规则文件以应用于我们的 Web ACL

    $ cat << EOF > ${SCRATCH}/waf-rules.json
    [
        {
          "Name": "AWS-AWSManagedRulesCommonRuleSet",
          "Priority": 0,
          "Statement": {
            "ManagedRuleGroupStatement": {
              "VendorName": "AWS",
              "Name": "AWSManagedRulesCommonRuleSet"
            }
          },
          "OverrideAction": {
            "None": {}
          },
          "VisibilityConfig": {
            "SampledRequestsEnabled": true,
            "CloudWatchMetricsEnabled": true,
            "MetricName": "AWS-AWSManagedRulesCommonRuleSet"
          }
        },
        {
          "Name": "AWS-AWSManagedRulesSQLiRuleSet",
          "Priority": 1,
          "Statement": {
            "ManagedRuleGroupStatement": {
              "VendorName": "AWS",
              "Name": "AWSManagedRulesSQLiRuleSet"
            }
          },
          "OverrideAction": {
            "None": {}
          },
          "VisibilityConfig": {
            "SampledRequestsEnabled": true,
            "CloudWatchMetricsEnabled": true,
            "MetricName": "AWS-AWSManagedRulesSQLiRuleSet"
          }
        }
    ]
    EOF

    这将启用核心(常用)和 SQL AWS 托管规则集。

  2. 使用我们上面指定的规则创建 AWS WAF Web ACL

    $ WAF_ARN=$(aws wafv2 create-web-acl \
      --name ${CLUSTER}-waf \
      --region ${REGION} \
      --default-action Allow={} \
      --scope REGIONAL \
      --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=${CLUSTER}-waf-metrics \
      --rules file://${SCRATCH}/waf-rules.json \
      --query 'Summary.ARN' \
      --output text)
  3. 使用 AWS WAF Web ACL ARN 注释 Ingress 资源

    $ oc annotate -n hello-world ingress.networking.k8s.io/hello-openshift-alb \
      alb.ingress.kubernetes.io/wafv2-acl-arn=${WAF_ARN}
  4. 等待 10 秒钟以使规则生效,并测试应用程序是否仍然有效

    $ curl "http://${INGRESS}"
    示例输出
    Hello OpenShift!
  5. 测试 WAF 是否拒绝错误请求

    $ curl -X POST "http://${INGRESS}" \
      -F "user='<script><alert>Hello></alert></script>'"
    示例输出
    <html>
    <head><title>403 Forbidden</title></head>
    <body>
    <center><h1>403 Forbidden</h1></center>
    </body>
    </html

    AWS WAF 集成的激活有时可能需要几分钟。如果您没有收到403 Forbidden错误,请等待几秒钟后再试。

    预期结果是403 Forbidden错误,这意味着 AWS WAF 正在保护您的应用程序。