---
# System prepended metadata

title: Day3 - Flux Multi-Tenancy
tags: [workshop]

---

# Flux Multi-Tenancy & Security Hands-on

Tasks

- Multi-tenancy lockdown
  - Configure the Flux controllers with multi-tenancy lockdown
  - Create service accounts and RBAC for tenant namespaces
  - Assign service accounts to Flux objects
- Secrets management
  - Configure the Age keys
  - Enable SOPS decryption for Flux
  - Encrypt secrets with SOPS in Git


## Flux Multi-Tenancy

Switch to the `flux-workshop` repository and follow the steps below.

### Enable the multi-tenancy lockdown

Add the following patches to the `clusters/dev-cluster/flux-system/kustomization.yaml`:

```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - gotk-components.yaml
  - gotk-sync.yaml
patches:
  - patch: |
      - op: add
        path: /spec/template/spec/containers/0/args/-
        value: --no-cross-namespace-refs=true      
    target:
      kind: Deployment
      name: "(kustomize-controller|helm-controller|notification-controller|image-reflector-controller|image-automation-controller)"
  - patch: |
      - op: add
        path: /spec/template/spec/containers/0/args/-
        value: --no-remote-bases=true      
    target:
      kind: Deployment
      name: "kustomize-controller"
  - patch: |
      - op: add
        path: /spec/template/spec/containers/0/args/-
        value: --default-service-account=flux      
    target:
      kind: Deployment
      name: "(kustomize-controller|helm-controller)"
  - patch: |
      - op: add
        path: /spec/serviceAccountName
        value: kustomize-controller      
    target:
      kind: Kustomization
      name: "flux-system"
```

Assign a service account to the Flux Kustomizations inside `clusters/dev-cluster/`:

```yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
spec:
  serviceAccountName: kustomize-controller
```

Commit the changes to the `flux-workshop` repository:

```shell
git add -A
git commit -m "Enable multi-tenancy lockdown"
git push origin main
```

After the changes are applied, the apps reconciliations should fail due to the lack of permissions.

```shell
flux get all -A
```

### Create service account and RBAC for the apps namespace

Add the following RBAC definitions in `apps/rbac.yaml`:

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: flux
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: flux-apps
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: admin
subjects:
  - kind: ServiceAccount
    name: flux
```

Commit the changes to the `flux-workshop` repository:

```shell
git add -A
git commit -m "Add service account and RBAC for apps namespace"
git push origin main
```

Wait for the apps reconciliation to succeed:

```shell
flux -n apps get all
```

## Flux Secrets Management

Install the [SOPS](https://github.com/getsops/sops) and [Age encryption](https://github.com/FiloSottile/age) tools on your machine.

```shell=
# Download SOPS
curl -LO https://github.com/getsops/sops/releases/download/v3.9.4/sops-v3.9.4.linux.amd64

# Move the SOPS binary in to your PATH
mv sops-v3.9.4.linux.amd64 /usr/local/bin/sops

# Make the SOPS binary executable
chmod +x /usr/local/bin/sops

# Install Age
apt install age

# Or download Age from
curl -LO https://github.com/FiloSottile/age/releases/download/v1.2.1/age-v1.2.1-linux-arm64.tar.gz
```

### Configure the Age keys

Generate a new Age key pair:

```shell
age-keygen -o flux.agekey
```

Export the public key:

```shell
export SOPS_AGE_RECIPIENTS=$(age-keygen -y flux.agekey)
```

Create a Kubernetes secret with the Age private key:

```shell
kubectl -n flux-system create secret generic sops-age \
  --from-file=flux.agekey=flux.agekey
```

You can now move the `flux.agekey` to a secure location.

### Enable SOPS decryption for the Flux Kustomizations

Add the following `decryption` section to the `clusters/dev-cluster/apps.yaml`:

```yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: apps
spec:
  decryption:
    provider: sops
    secretRef:
      name: sops-age
```

### Encrypt secrets with SOPS

Generate the GitLab auth secret to `apps/git-auth.yaml`:

```shell
flux -n apps create secret git apps-git-auth \
--url=https://gitlab.com/$GITLAB_USER/flux-workshop-apps.git \
--username=flux \
--password=$GITLAB_TOKEN \
--export > apps/gitlab-auth.yaml
```

Encrypt the secret with SOPS:

```shell
sops \
--age=${SOPS_AGE_RECIPIENTS} \
--encrypt \
--encrypted-regex '^(data|stringData)$' \
--in-place apps/git-auth.yaml
```


Commit the changes to the `flux-workshop` repository:

```shell
git add -A
git commit -m "Enable SOPS decryption for apps"
git push origin main
```

After the changes are applied, the apps reconciliations should succeed:

```shell
flux reconcile ks apps
```

Verify that the `apps-git-auth` secret is now managed by Flux:

```shell
flux -n apps trace Secret/apps-git-auth
```
