Issuing wildcard certificates on Kubernetes Gateway API (Part 2/2)
Tags: kubernetes, externaldns, cloudflare
Published: 2023-08-23 10:37:43



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlkugb5v7s83myibzgov.png)



If you have followed part1 you should should have cert-manager already running.

All the files are available on github: https://github.com/angjelo/cloud-infra

Let's see how we can build the following infrustrcture by using cilium and the gateway api.

Initially we need to create a gateway class and specify the controller that our gateway will be using, I am using cilium on my cluster that's why I have set `controllerName: io.cilium/gateway-controller`
```yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
  name: cillium-gateway-class
spec:
  controllerName: io.cilium/gateway-controller
```

After you have successfully created the gateway controller lets define the gateway which will be our entrypoint.
Few things:
-  The `annotations` field allows you to attach additional metadata to the resource. In this case, an annotation is used to specify the cluster issuer for certificates issued by Cert-Manager (a Kubernetes add-on for certificate management)
- `cert-manager.io/cluster-issuer:cloudflare-domain-issuer` refers to the cluster-issuer that we created in part1
- The secret used in the field `certificateRefs` is defined in the certificate.yml

```yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: fine-ops-gateway
  annotations:
    cert-manager.io/cluster-issuer: cloudflare-domain-issuer
spec:
  gatewayClassName: cillium-gateway-class
  listeners:
    - name: https
      hostname: "*.fine-ops.com"
      port: 443
      protocol: HTTPS
      tls:
        mode: Terminate
        certificateRefs:
        - kind: Secret
          name: fine-ops
```

if we execute `kubectl get svc` then we shoulld see a public IP assigned to our gateway, if you are on aws usually you will get an ELB address that you can use to point to point your `CNAME` cloudflare

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ig1k2sxjjnkn3v3iyy5i.png)
<details>
<summary><strong>⚠️ Important Note:</strong></summary>
if you delete and recreate the gateway the load balancer will populate a new ip which you need to update manually on cloudflare
</details>
<br>
Now that we have defined our main entry point lets create our
- `tls-route`
- `service` 
- deployment for `test-app1`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/urwdlmbqmw095ndzsr1v.png)

This will be the nginx app deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app1
  namespace: default
  labels:
    app: test-app1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test-app1
  template:
    metadata:
      labels:
        app: test-app1
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        imagePullPolicy: Always
```

`kubectl apply -f test-app1-deployment.yml`

To view if the pods are deployed successfully `kubectl get pods`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8q0701g0oits14h7yaq.png)

Now is time to create a service to expose the port internally in kubernetes:
```yaml
apiVersion: v1
kind: Service
metadata:
  name: test-app1
  namespace: default
  labels:
    app: test-app1
spec:
  ports:
  - port: 80
    name: http
  selector:
    app: test-app1
```
`kubectl get svc` to see if the service was created

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypq5or47pkmg3lfffxk8.png)

Se we can see that test-app1 has been exposed to an internal IP. Now it's time create the `tls-route` and attach it to the service that we exposed earlier
```yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: test-app-1
spec:
  parentRefs:
  - name: fine-ops-gateway
    sectionName: https
  hostnames:
    - "fe-1.fine-ops.com"
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /
        method: GET
      backendRefs:
      - name: test-app1
        port: 80
```

Lets break down some keypoints in the yaml:

- `parentRefs` refers to the gateway name that we created earlier (fine-ops-gateway)
- `We are referencing the service created earlier for test-app1`
validate that the route was created: `kubectl get httproutes`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzhhy2bx1xg2pytiep78.png)

Now that we have have created our http route, we can try to access the service on `https://fe-1.fine-ops.com` (make sure you have created an A record that points the Loadbalancer IP of the cilium gateway)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqe6touk7la22arfuu8z.png)

Now that we have deployed `fe-1.fine-ops.com` it time to deploy `fe-2.fine-ops.com`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bspt97cg7g9j9uxdlke2.png)

Let's start again by creating the second deployment, similar to the previous nginx deployment but the app name is different this time

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app2
  namespace: default
  labels:
    app: test-app2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-app2
  template:
    metadata:
      labels:
        app: test-app2
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        imagePullPolicy: Always
```

After verifying that the pods are running it is time to create the service to internally expose the port to kubernetes
```yaml
apiVersion: v1
kind: Service
metadata:
  name: test-app2
  namespace: default
  labels:
    app: test-app2
spec:
  ports:
  - port: 90
    name: http
    targetPort: 80
  selector:
    app: test-app2
```

Not it is time to create the TLS route for fe-2.fine-ops.com
```yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: http-app-2
spec:
  parentRefs:
  - name: fine-ops-gateway
    namespace: default
  hostnames:
    - "fe-2.fine-ops.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
      method: GET
    backendRefs:
    - name: test-app2
      port: 90
```

`kubectl get httproutes` should display these routes
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pwrxcp11k1c63q2qewps.png)

Lastly we need to add a new A for fe-2.fine-ops.com record to point to the load balancer IP,this is how the records should look like in cloudflare

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9d1v0p4fz7ehr00hjyx5.png)

Now you can visit fe-2.yourdomain.com

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m5tyntqy3if3flt8yh9g.png)