Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added docs about how to secure a Service using an Ingress #306

Merged
merged 16 commits into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions cmd/gameserverapi/deployment/secured/deploy_mtls.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: thundernetes-gameserverapi
namespace: thundernetes-system
labels:
app: thundernetes-gameserverapi
spec:
selector:
matchLabels:
app: thundernetes-gameserverapi
replicas: 1
template:
metadata:
labels:
app: thundernetes-gameserverapi
spec:
containers:
- image: ghcr.io/playfab/thundernetes-gameserverapi:${IMAGE_TAG}
name: gameserverapi
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 500Mi
limits:
cpu: 100m
memory: 500Mi
ports:
- containerPort: 5001
hostPort: 5001
livenessProbe:
httpGet:
path: /healthz
port: 5001
initialDelaySeconds: 3
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: 5001
initialDelaySeconds: 3
periodSeconds: 10
serviceAccountName: thundernetes-controller-manager
terminationGracePeriodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: thundernetes-gameserverapi
namespace: thundernetes-system
spec:
selector:
app: thundernetes-gameserverapi
ports:
- protocol: TCP
port: 5001
targetPort: 5001
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: thundernetes-gameserverapi-ingress
namespace: thundernetes-system
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
nginx.ingress.kubernetes.io/auth-tls-secret: "thundernetes-system/tls-secret"
spec:
ingressClassName: nginx
tls:
- hosts:
- ${HOST}
- secretName: tls-secret
rules:
- host: ${HOST}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: thundernetes-gameserverapi
port:
number: 5001
77 changes: 77 additions & 0 deletions docs/howtos/serviceingress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
layout: default
title: Protect your Services using an Ingress
parent: How to's
nav_order: 11
---

# Protect your Services using an Ingress

It is possible to secure any service in the cluster using a Kubernetes [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/), this way it can terminate any requests that don't have the right credentials. Kubernetes doesn't have an Ingress implementation out of the box, so you have to choose an [Ingress Controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) to install. An Ingress can provide multiple ways to authenticate requests, depending on the implementation, for example, the [Nginx Ingress Controller](https://kubernetes.github.io/ingress-nginx/deploy/) allows you to use: basic authentication, mutual TLS (mTLS) or use external authentication services. In the following section we show how to use an Ingress to enable mTLS for the Game Server API.

## Enabling mTLS for the Game Server API

When you deploy an Ingress you can use annotations to enable the authentication of both the server and the client, all of this will happen at the Ingress level, so you don't have to change any code in the service. Note that this needs you to have a domain you can use for your service. For this, you have to create a Kubernetes Secret containing the server's private and public key, and the public key from the Certificate Authority (CA). For testing purposes, or for private use, you can create your own CA and use it to sign all your certificates. To do all of this you can follow the next steps:

### Step 1: Install Thundernetes and the Nginx Ingress Controller on your cluster
```
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml

kubectl apply -f https://raw.githubusercontent.com/PlayFab/thundernetes/main/installfiles/operator.yaml

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.0/deploy/static/provider/cloud/deploy.yaml
```

### Step 2: Create a key pair to act as your Certificate Authority (CA)

```
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 1000 -nodes -subj '/CN=My Cert Authority'
```

### Step 3: Create key pairs for the server and for the client and sign them with the CA

```
# create and sign the server keys
openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN={the host of your server}' -addext "subjectAltName=DNS:{the host of your server}"

openssl x509 -req -sha256 -days 1000 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

# create and sign the client keys
openssl req -new -newkey rsa:4096 -keyout client.key -out client.csr -nodes -subj '/CN=Client'

openssl x509 -req -sha256 -days 1000 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt
```

### Step 4: Create a Kubernetes Secret

```
kubectl create secret generic -n thundernetes-system tls-certs --from-file=tls.crt=server.crt --from-file=tls.key=server.key --from-file=ca.crt=ca.crt
```

### Step 5: Deploy the Service and the Ingress

We have bundled the definitions to deploy the GameServer API in the [deployment/secured/deploy_mtls.yaml](https://github.com/PlayFab/thundernetes/blob/main/cmd/gameserverapi/deployment/secured/deploy_mtls.yaml) file, it includes the Deployment, the Service, and the Ingress needed for the mTLS to work. You have to check the name of the Secret referenced in the Ingress matches the one you created, replace the ```${IMAGE_TAG}``` for the current release, and also replace the ```${HOST}``` values for your domain. Then you just run:

```
kubectl apply -f {path to deploy_mtls.yaml}
```

### Step 6: Connect to the Game Server API

Now the Game Server API is exposed through the Ingress, to connect to it you have to get the Ingress' external IP, you can do this with this command:

```
kubectl get ingress thundernetes-gameserverapi-ingress -n thundernetes-system
```

The Ingress may take a minute before getting an IP, if you're running this locally it won't ever get one, but you can use [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) instead. Finally you can try a simple GET request providing the client keys to test that the API is working, note that you will have to add the public certificate of your CA to your trusted root certificates:

```
curl https://{ingress_IP}/api/v1/gameserverbuilds --cert client.crt --key client.key
```

Or, you can also skip the validation on the client side and only check that the server is verifying the client certificates, adding the ```-k``` or ```--insecure``` option:

```
curl https://{ingress_IP}/api/v1/gameserverbuilds --cert client.crt --key client.key -k
```