diff --git a/README.md b/README.md index 37aa83df39..3ca4e31395 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,9 @@ GKE is a managed Kubernetes platform that provides a more opinionated and seamle - [Basic External Ingress](./ingress/external-ingress-basic) - Deploy host-based routing through an internet-facing HTTP load balancer - [Basic Internal Ingress](./ingress/internal-ingress-basic) - Deploy host-based routing through a private, internal HTTP load balancer - [Secure Ingress](./ingress/secure-ingress) - Secure Ingress-hosted Services with HTTPS, Google-managed certificates, SSL policies, and HTTPS redirects. -- Multi-cluster Ingress - [IAP Ingress](./ingress/iap-ingress) - GKE Ingress with Identity-Aware Proxy based authentication. + - [CloudArmor Ingress](./ingress/cloudarmor-ingress) - GKE Ingress with Google CloudArmor policy protection. +- Multi-cluster Ingress - [Basic Multi-cluster Ingress](./multi-cluster-ingress/multi-cluster-ingress-basic) - Deploy applications across different clusters and different regions but retain a single global load balancer and public IP for global traffic management. - [Blue/Green Multi-cluster Ingress](./multi-cluster-ingress/multi-cluster-blue-green-cluster) - Deploy applications across multiple clusters in the same region, leveraging a single global load balancer and public IP for global traffic management, to support seamless cluster upgrades without impacting client access. - Services diff --git a/images/cloudarmor-ingress.png b/images/cloudarmor-ingress.png new file mode 100644 index 0000000000..d96cc5584a Binary files /dev/null and b/images/cloudarmor-ingress.png differ diff --git a/ingress/cloudarmor-ingress/README.md b/ingress/cloudarmor-ingress/README.md new file mode 100644 index 0000000000..708bb9ce8e --- /dev/null +++ b/ingress/cloudarmor-ingress/README.md @@ -0,0 +1,128 @@ +# Google Cloud Armor enabled ingress + +Following recipe provides a walk-through for setting up [GKE Ingress](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress) +with [Google Cloud Armor](https://cloud.google.com/armor) protection. + +Google Cloud Armor protects your applications and websites against denial of service and web attacks. +Since GKE Ingresses use **proxy-based** [Google Cloud HTTP(s) Load Balancers](https://cloud.google.com/load-balancing/docs/https), +**protection against L3 and L4 DDos attacks is enabled by default**. + +Applications can be also protected with Layer7 filtering by using Google Cloud Armor +[security policies](https://cloud.google.com/armor/docs/security-policy-overview). Once Google Cloud +Armor security policy is configured, it can be used to protect services associated with a given ingress. + +## Use cases + +* Protect backend services at the networking edge with Layer7 filtering rules + +## Relevant documentation + +* [Cloud Armor overview](https://cloud.google.com/armor) +* [Cloud Armor security policy](https://cloud.google.com/armor/docs/security-policy-overview) +* [GKE ingress overview](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress) + +## Versions & Compatibility + +* GKE version 1.19.10+ *(for GA of this feature)* +* Works with [External Ingress](https://cloud.google.com/kubernetes-engine/docs/how-to/load-balance-ingress) + *(single-cluster)* +* Tested and validated with GKE version 1.19.10 on Jul 2nd 2021 + +--- + +![cloudarmor-ingress](../../images/cloudarmor-ingress.png) + +Google Cloud Armor protection is integrated with ingress for GKE by leveraging [BackendConfig CRD](https://github.com/kubernetes/ingress-gce/tree/master/pkg/apis/backendconfig). +This object is associated with a given service and allows to specify configuration for HTTPs Load Balancer +that handles incoming traffic. Google Cloud Armor policy can be can be enabled for a service by specifying +`securityPolicy` block with `name` key that defines name of the policy that will be applied. + +**NOTE**: GKE creates [default backend](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress#default_backend) +service upon cluster creation. This default service returns `404` HTTP response code and is used +on any Ingress as a default destination for unmatched requests - unless `defaultBackend` field with custom +service is specified. Keep in mind that **GKE default backend service has no associated `BackendConfig` +by default**, so you need to configure CloudArmor policy for it explicitly. + +**NOTE**: applying `cloud.google.com/backend-config` annotation on an existing service, that is +associated with an existing Ingress, makes no changes on underlying backend service. +Refer to [following issue for details](https://github.com/kubernetes/ingress-gce/issues/1503). + +## Walk-through + +Prerequisites: + +* GKE cluster up and running *(check [Prerequisite: GKE setup](#prerequisite-gke-setup) below)* +* Google Cloud Armor policy configured *(check [Configuring Google Cloud Armor security policies](https://cloud.google.com/armor/docs/configure-security-policies) + guide)* + +Steps: + +1. (Optional) Enable Google CloudArmor policy on a `default-http-backend` service + + * Create `BackendConfig` in a `kube-system` namespace. Substitute example policy name with your + CloudArmor policy name + + ```sh + cat << EOF | kubectl apply -f - -n kube-system + apiVersion: cloud.google.com/v1 + kind: BackendConfig + metadata: + name: cloudarmor-test + spec: + securityPolicy: + name: cloudarmor-test + EOF + ``` + + * Annotate `default-http-backend` service in a `kube-system` namespace with a newly created `BackendConfig` + + ```sh + kubectl annotate services default-http-backend \ + beta.cloud.google.com/backend-config='{"default": "cloudarmor-test"}' -n kube-system + ``` + +2. Replace `$POLICY_NAME` variable in `cloudarmor-ingress.yaml` file with your Google CloudArmor +policy name. + + ```sh + sed -i '.bak' 's/$POLICY_NAME/cloudarmor-test/g' cloudarmor-ingress.yaml + ``` + +3. Apply `cloudarmor-ingress.yaml` file + + ```sh + $ kubectl apply -f cloudarmor-ingress.yaml + ingress.networking.k8s.io/cloudarmor-test created + backendconfig.cloud.google.com/cloudarmor-test created + service/whereami created + deployment.apps/whereami created + $ + ``` + +4. Wait until all created objects reach desired state + +5. Verify and enjoy + +### Prerequisite: GKE setup + +1. Enable GKE API + + ```sh + gcloud services enable container.googleapis.com + ``` + +2. Create simple zonal GKE cluster for tests + + ```sh + gcloud container clusters create cluster-test \ + --zone europe-central2-a \ + --release-channel regular \ + --enable-ip-alias + ``` + +3. Configure client credentials for a new cluster + + ```sh + gcloud container clusters get-credentials cluster-test \ + --zone europe-central2-a + ```` diff --git a/ingress/cloudarmor-ingress/cloudarmor-ingress.yaml b/ingress/cloudarmor-ingress/cloudarmor-ingress.yaml new file mode 100644 index 0000000000..370c8a37df --- /dev/null +++ b/ingress/cloudarmor-ingress/cloudarmor-ingress.yaml @@ -0,0 +1,79 @@ + +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: cloudarmor-test +spec: + rules: + - http: + paths: + - path: /whereami + backend: + serviceName: whereami + servicePort: 80 +--- +apiVersion: cloud.google.com/v1 +kind: BackendConfig +metadata: + name: cloudarmor-test +spec: + securityPolicy: + name: $POLICY_NAME +--- +apiVersion: v1 +kind: Service +metadata: + name: whereami + annotations: + cloud.google.com/neg: '{"ingress": true}' + cloud.google.com/backend-config: '{"default": "cloudarmor-test"}' +spec: + type: ClusterIP + selector: + app: whereami + ports: + - port: 80 + protocol: TCP + targetPort: 8080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: whereami +spec: + replicas: 3 + selector: + matchLabels: + app: whereami + template: + metadata: + labels: + app: whereami + spec: + containers: + - name: whereami + image: gcr.io/google-samples/whereami:v1.0.1 + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /healthz + port: 8080 + scheme: HTTP + initialDelaySeconds: 5 + timeoutSeconds: 1