×

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

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

先决条件

  • 一个 ROSA (HCP 或 Classic) 集群。

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

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

环境设置

  • 准备环境变量

    $ export DOMAIN=apps.example.com (1)
    $ export AWS_PAGER=""
    $ export CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
    $ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    $ export SCRATCH="/tmp/${CLUSTER}/cloudfront-waf"
    $ mkdir -p ${SCRATCH}
    $ echo "Cluster: ${CLUSTER}, Region: ${REGION}, AWS Account ID: ${AWS_ACCOUNT_ID}"
    1 替换为要用于IngressController 的自定义域名。

    上一条命令的“集群”输出可能是您的集群名称、集群的内部 ID 或集群的域名前缀。如果您希望使用其他标识符,您可以手动运行以下命令设置此值:

    $ export CLUSTER=my-custom-value

设置辅助 Ingress 控制器

需要配置辅助 Ingress 控制器,以将受 WAF 保护的外部流量与标准(和默认)集群 Ingress 控制器隔离开。

先决条件
  • 您自定义域名的公开信任的 SAN 或通配符证书,例如 CN=*.apps.example.com

    Amazon CloudFront 使用 HTTPS 与集群的辅助 Ingress 控制器通信。正如Amazon CloudFront 文档中所述,您不能使用自签名证书进行 CloudFront 和集群之间的 HTTPS 通信。Amazon CloudFront 会验证证书是否由受信任的证书颁发机构颁发。

步骤
  1. 从私钥和公钥创建新的 TLS 密钥,其中 fullchain.pem 是您的完整通配符证书链(包括任何中间证书),privkey.pem 是您的通配符证书的私钥。

    示例
    $ oc -n openshift-ingress create secret tls waf-tls --cert=fullchain.pem --key=privkey.pem
  2. 创建新的IngressController资源

    waf-ingress-controller.yaml示例
    apiVersion: operator.openshift.io/v1
    kind: IngressController
    metadata:
      name: cloudfront-waf
      namespace: openshift-ingress-operator
    spec:
      domain: apps.example.com (1)
      defaultCertificate:
        name: waf-tls
      endpointPublishingStrategy:
        loadBalancer:
          dnsManagementPolicy: Unmanaged
          providerParameters:
            aws:
              type: NLB
            type: AWS
          scope: External
        type: LoadBalancerService
      routeSelector: (2)
        matchLabels:
         route: waf
    1 替换为要用于IngressController 的自定义域名。
    2 过滤 Ingress 控制器服务的路由集。在本教程中,我们将使用waf路由选择器,但如果未提供任何值,则不会进行任何过滤。
  3. 应用IngressController

    示例
    $ oc apply -f waf-ingress-controller.yaml
  4. 验证您的 IngressController 是否已成功创建外部负载均衡器

    $ oc -n openshift-ingress get service/router-cloudfront-waf
    示例输出
    NAME                    TYPE           CLUSTER-IP      EXTERNAL-IP                                                                     PORT(S)                      AGE
    router-cloudfront-waf   LoadBalancer   172.30.16.141   a68a838a7f26440bf8647809b61c4bc8-4225395f488830bd.elb.us-east-1.amazonaws.com   80:30606/TCP,443:31065/TCP   2m19s

配置 AWS WAF

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

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

    $ 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_WACL=$(aws wafv2 create-web-acl \
      --name cloudfront-waf \
      --region ${REGION} \
      --default-action Allow={} \
      --scope CLOUDFRONT \
      --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=${CLUSTER}-waf-metrics \
      --rules file://${SCRATCH}/waf-rules.json \
      --query 'Summary.Name' \
      --output text)

配置 Amazon CloudFront

  1. 检索新创建的自定义 Ingress 控制器的 NLB 主机名

    $ NLB=$(oc -n openshift-ingress get service router-cloudfront-waf \
      -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
  2. 将您的证书导入 Amazon Certificate Manager,其中 cert.pem 是您的通配符证书,fullchain.pem 是您的通配符证书链,privkey.pem 是您的通配符证书的私钥。

    无论您的集群部署在哪个区域,都必须将此证书导入us-east-1,因为 Amazon CloudFront 是一项全球性 AWS 服务。

    示例
    $ aws acm import-certificate --certificate file://cert.pem \
      --certificate-chain file://fullchain.pem \
      --private-key file://privkey.pem \
      --region us-east-1
  3. 登录AWS 控制台以创建 CloudFront 分发。

  4. 使用以下信息配置 CloudFront 分发

    如果下表中未指定选项,请保留默认值(可能是空白)。

    选项

    源域名

    上一条命令的输出 [1]

    名称

    rosa-waf-ingress [2]

    查看器协议策略

    将 HTTP 重定向到 HTTPS

    允许的 HTTP 方法

    GET、HEAD、OPTIONS、PUT、POST、PATCH、DELETE

    缓存策略

    CachingDisabled

    源请求策略

    AllViewer

    Web 应用防火墙 (WAF)

    启用安全保护

    使用现有的 WAF 配置

    true

    选择 Web ACL

    cloudfront-waf

    备用域名 (CNAME)

    *.apps.example.com [3]

    自定义 SSL 证书

    选择您在上一步中导入的证书 [4]

    1. 运行echo ${NLB}以获取源域名。

    2. 如果您有多个集群,请确保源名称唯一。

    3. 这应与您用于创建自定义 Ingress 控制器的通配符域名匹配。

    4. 这应与上面输入的备用域名匹配。

  5. 检索 Amazon CloudFront 分发端点

    $ aws cloudfront list-distributions --query "DistributionList.Items[?Origins.Items[?DomainName=='${NLB}']].DomainName" --output text
  6. 使用指向上面步骤中 Amazon CloudFront 分发端点的 CNAME 更新自定义通配符域的 DNS。

    示例
    *.apps.example.com CNAME d1b2c3d4e5f6g7.cloudfront.net

部署示例应用程序

  1. 通过运行以下命令为您的示例应用程序创建一个新项目

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

    $ oc -n hello-world new-app --image=docker.io/openshift/hello-openshift
  3. 为应用程序创建一个路由,指定您的自定义域名

    示例
    $ oc -n hello-world create route edge --service=hello-openshift hello-openshift-tls \
    --hostname hello-openshift.${DOMAIN}
  4. 标记路由以将其接入您的自定义 Ingress 控制器

    $ oc -n hello-world label route.route.openshift.io/hello-openshift-tls route=waf

测试 WAF

  1. 测试该应用程序是否可在 Amazon CloudFront 后面访问

    示例
    $ curl "https://hello-openshift.${DOMAIN}"
    示例输出
    Hello OpenShift!
  2. 测试 WAF 是否拒绝错误请求

    示例
    $ curl -X POST "https://hello-openshift.${DOMAIN}" \
      -F "user='<script><alert>Hello></alert></script>'"
    示例输出
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
    <TITLE>ERROR: The request could not be satisfied</TITLE>
    </HEAD><BODY>
    <H1>403 ERROR</H1>
    <H2>The request could not be satisfied.</H2>
    <HR noshade size="1px">
    Request blocked.
    We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
    <BR clear="all">
    If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
    <BR clear="all">
    <HR noshade size="1px">
    <PRE>
    Generated by cloudfront (CloudFront)
    Request ID: nFk9q2yB8jddI6FZOTjdliexzx-FwZtr8xUQUNT75HThPlrALDxbag==
    </PRE>
    <ADDRESS>
    </ADDRESS>
    </BODY></HTML>

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