17
loading...
This website collects cookies to deliver better user experience
With Workload Identity, you can configure a Kubernetes service account to act as a Google service account. Pods running as the Kubernetes service account will automatically authenticate as the Google service account when accessing Google Cloud APIs.
infra/plan/service-account.tf
.resource "google_service_account" "web" {
account_id = "cloud-sql-access"
display_name = "Service account used to access cloud sql instance"
}
resource "google_project_iam_binding" "cloudsql_client" {
role = "roles/cloudsql.client"
members = [
"serviceAccount:cloud-sql-access@${data.google_project.project.project_id}.iam.gserviceaccount.com",
]
}
data "google_project" "project" {
}
infra/k8s/data/service-account.yaml
:apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
iam.gke.io/gcp-service-account: cloud-sql-access@<PROJECT_ID>.iam.gserviceaccount.com
name: cloud-sql-access
cd infra/plan
terraform apply
gcloud container clusters get-credentials private --region $REGION --project $PROJECT_ID
$ kubectl create namespace wordpress
sed -i "s/<PROJECT_ID>/$PROJECT_ID/g;" infra/k8s/data/service-account.yaml
$ kubectl create -f infra/k8s/data/service-account.yaml -n wordpress
gcloud iam service-accounts add-iam-policy-binding \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:$PROJECT_ID.svc.id.goog[wordpress/cloud-sql-access]" \
cloud-sql-access@$PROJECT_ID.iam.gserviceaccount.com
infra/k8s/data/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: cloud-sql-proxy
name: cloud-sql-proxy
spec:
selector:
matchLabels:
app: cloud-sql-proxy
strategy: {}
replicas: 3
template:
metadata:
labels:
app: cloud-sql-proxy
spec:
serviceAccountName: cloud-sql-access
containers:
- name: cloud-sql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.23.0
ports:
- containerPort: 3306
protocol: TCP
envFrom:
- configMapRef:
name: cloud-sql-instance
command:
- "/cloud_sql_proxy"
- "-ip_address_types=PRIVATE"
- "-instances=$(CLOUD_SQL_PROJECT_ID):$(CLOUD_SQL_INSTANCE_REGION):$(CLOUD_SQL_INSTANCE_NAME)=tcp:0.0.0.0:3306"
securityContext:
runAsNonRoot: true
resources:
requests:
memory: 2Gi
cpu: 1
infra/k8s/data/config-map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cloud-sql-instance
data:
CLOUD_SQL_INSTANCE_NAME: <CLOUD_SQL_INSTANCE_NAME>
CLOUD_SQL_INSTANCE_REGION: <CLOUD_SQL_REGION>
CLOUD_SQL_PROJECT_ID: <CLOUD_SQL_PROJECT_ID>
infra/k8s/data/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: cloud-sql-proxy
name: cloud-sql-proxy
spec:
ports:
- port: 3306
protocol: TCP
name: cloud-sql-proxy
targetPort: 3306
selector:
app: cloud-sql-proxy
cd infra/plan
sed -i "s/<CLOUD_SQL_PROJECT_ID>/$PROJECT_ID/g;s/<CLOUD_SQL_INSTANCE_NAME>/$(terraform output cloud-sql-instance-name | tr -d '"')/g;s/<CLOUD_SQL_REGION>/$REGION/g;" ../k8s/data/config-map.yaml
$ kubectl create -f ../k8s/data -n wordpress
$ kubectl get pods -l app=cloud-sql-proxy -n wordpress
NAME READY STATUS RESTARTS AGE
cloud-sql-proxy-fb9968d49-hqlwb 1/1 Running 0 4s
cloud-sql-proxy-fb9968d49-wj498 1/1 Running 0 5s
cloud-sql-proxy-fb9968d49-z95zw 1/1 Running 0 4s
$ kubectl logs cloud-sql-proxy-fb9968d49-hqlwb -n wordpress
2021/06/23 14:43:21 current FDs rlimit set to 1048576, wanted limit is 8500. Nothing to do here.
2021/06/23 14:43:25 Listening on 0.0.0.0:3306 for <PROJECT_ID>:<REGION>:<CLOUD_SQL_INSTANCE_NAME>
2021/06/23 14:43:25 Ready for new connections
infra/k8s/web/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
spec:
containers:
- image: wordpress
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: cloud-sql-proxy:3306
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_NAME
value: wordpress
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: password
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
livenessProbe:
initialDelaySeconds: 30
httpGet:
port: 80
path: /wp-admin/install.php # at the very beginning, this is the only accessible page. Don't forget to change to /wp-login.php
readinessProbe:
httpGet:
port: 80
path: /wp-admin/install.php
resources:
requests:
cpu: 1000m
memory: 2Gi
limits:
cpu: 1200m
memory: 2Gi
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wordpress
infra/k8s/web/service.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress
annotations:
cloud.google.com/neg: '{"ingress": true}'
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app: wordpress
The cloud.google.com/neg
annotation specifies that port 80 will be associated with a zonal network endpoint group (NEG). See Container-native load balancing for information on the benefits, requirements, and limitations of container-native load balancing.
infra/k8s/web/volume-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
infra/k8s/web/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.global-static-ip-name: "wordpress"
kubernetes.io/ingress.class: "gce"
name: wordpress
spec:
defaultBackend:
service:
name: wordpress
port:
number: 80
rules:
- http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: wordpress
port:
number: 80
The kubernetes.io/ingress.global-static-ip-name
annotation specifies the name of the global IP address resource to be associated with the HTTP(S) Load Balancer. [2]
cd infra/k8s
$ kubectl create secret generic mysql \
--from-literal=password=$(gcloud secrets versions access latest --secret=wordpress-admin-user-password --project $PROJECT_ID) -n wordpress
gcloud compute addresses create wordpress --global
$ kubectl create -f web -n wordpress
$ kubectl get pods -l app=wordpress -n wordpress
NAME READY STATUS RESTARTS AGE
wordpress-6d58d85845-2d7x2 1/1 Running 0 10m
$ kubectl get ingress -n wordpress
NAME CLASS HOSTS ADDRESS PORTS AGE
wordpress <none> * 34.117.187.51 80 16m
ìnfra/plan/cloud-armor.tf
:resource "google_compute_security_policy" "wordpress" {
name = "wordpress"
rule {
action = "allow"
priority = "1000"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = var.authorized_source_ranges
}
}
description = "Allow access to authorized source ranges"
}
rule {
action = "deny(403)"
priority = "2147483647"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "default rule"
}
}
cd infra/plan
terraform apply
BackendConfig custom resource definition (CRD) allows us to further customize the load balancer. This CRD allows us to define additional load balancer features hierarchically, in a more structured way than annotations. [3]
infra/k8s/web/backend.yaml
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
name: wordpress
spec:
securityPolicy:
name: wordpress
kubectl create -f infra/k8s/web/backend.yaml -n wordpress
cloud.google.com/backend-config: '{"default": "wordpress"}'
in the wordpress service:kubectl apply -f infra/k8s/web/service.yaml -n wordpress
gcloud compute security-policies rules update 1000 \
--security-policy wordpress \
--src-ip-ranges "85.56.40.96"
curl http://34.117.187.51/
<!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden
gcloud compute security-policies rules update 1000 \
--security-policy wordpress \
--src-ip-ranges $(curl -s http://checkip.amazonaws.com/)
curl http://34.117.187.51/
<!doctype html>
<html lang="en-GB" >
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>admin – Just another WordPress site</title>
IAP is integrated through Ingress for GKE. This integration enables you to control resource-level access for employees instead of using a VPN. [1]
CLIENT_ID_KEY=<CLIENT_ID_KEY>
CLIENT_SECRET_KEY=<CLIENT_SECRET_KEY>
kubectl create secret generic wordpress --from-literal=client_id=$CLIENT_ID_KEY \
--from-literal=client_secret=$CLIENT_SECRET_KEY \
-n wordpress
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
name: wordpress
spec:
iap:
enabled: true
oauthclientCredentials:
secretName: wordpress
securityPolicy:
name: wordpress
kubectl apply -f infra/k8s/web/backend-config.yaml -n wordpress
Google-managed SSL certificates are Domain Validation (DV) certificates that Google Cloud obtains and manages for your domains. They support multiple hostnames in each certificate, and Google renews the certificates automatically. [4]
infra/k8s/web/ssl.yaml
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: wordpress
spec:
domains:
- <DOMAIN_NAME>
export PUBLIC_DNS_NAME=
export PUBLIC_DNS_ZONE_NAME=
gcloud dns record-sets transaction start --zone=$PUBLIC_DNS_ZONE_NAME
gcloud dns record-sets transaction add $(gcloud compute addresses list --filter=name=wordpress --format="value(ADDRESS)") --name=wordpress.$PUBLIC_DNS_NAME. --ttl=300 --type=A --zone=$PUBLIC_DNS_ZONE_NAME
gcloud dns record-sets transaction execute --zone=$PUBLIC_DNS_ZONE_NAME
sed -i "s/<DOMAIN_NAME>/wordpress.$PUBLIC_DNS_NAME/g;" infra/k8s/web/ssl.yaml
kubectl create -f infra/k8s/web/ssl.yaml -n wordpress
networking.gke.io/managed-certificates: "wordpress"
in your ingress resource.infra/k8s/web/frontend-config.yaml
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
name: wordpress
spec:
redirectToHttps:
enabled: true
responseCodeName: MOVED_PERMANENTLY_DEFAULT
kubectl create -f infra/k8s/web/frontend-config.yaml -n wordpress
networking.gke.io/v1beta1.FrontendConfig: "wordpress"
in your ingress resource.curl -s http://wordpress.<HIDDEN>.stack-labs.com/
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://wordpress.<HIDDEN>.stack-labs.com/">here</A>.
</BODY></HTML>
Compute Engine > Network Endpoint Group
.terraform destroy
gcloud dns record-sets transaction remove $(gcloud compute addresses list --filter=name=wordpress --format="value(ADDRESS)") --name=wordpress.$PUBLIC_DNS_NAME. --ttl=300 --type=A --zone=$PUBLIC_DNS_ZONE_NAME
gcloud dns record-sets transaction execute --zone=$PUBLIC_DNS_ZONE_NAME
gcloud compute addresses delete wordpress
gcloud secrets delete wordpress-admin-user-password