Deploy a Kubernetes Cluster Across NETWAYS Web Services and AWS With Claudie

27 May, 2026

Daniel Bodky
Daniel Bodky
Senior Platform Advocate

Daniel kam nach Abschluss seines Studiums im Oktober 2021 zu NETWAYS und beriet zwei Jahre lang Kunden zu den Themen Icinga2 und Kubernetes, bevor es ihn weiter zu Managed Services zog. Seitdem redet und schreibt er viel über cloud-native Technologien und ihre spannenden Anwendungsfälle und gibt sein Bestes, um Neues und Interessantes rund um Kubernetes zu vermitteln. Nebenher schreibt er in seiner Freizeit kleinere Tools für verschiedenste Einsatzgebiete, nimmt öfters mal ein Buch in die Hand oder widmet sich seinem viel zu großen Berg Lego. In der wärmeren Jahreszeit findet man ihn außerdem oft auf dem Fahrrad oder beim Wandern.

by | May 27, 2026

This guide walks through building a 7-node Kubernetes cluster spread across NETWAYS Web Services (OpenStack) and AWS, managed end-to-end by Claudie.


Samuel Stolicny

This article has been created in collaboration with Samuel Stoličný from Berops. You can find him on LinkedIn if you want to learn more about Claudie.


Why This Setup

Running the same cluster across a German OpenStack provider and a hyperscaler gives you two things that are hard to get from either one alone. NWS keeps your core workloads on EU-owned infrastructure with predictable pricing and direct access to NETWAYS’ OpenStack expertise, which matters for data-sovereignty and operational support.

AWS puts extra capacity and managed features (Route 53, Managed Databases, Message Queues, Lambda) one hop away over the cluster network, so you can reach for them without moving the whole cluster. Claudie stitches the two providers together into one Kubernetes control plane, so applications schedule across both like it’s a single cloud.

What You Get

  • 3 control-plane nodes (1 NWS, 2 AWS) which gives etcd a proper quorum (tolerates one node loss).
  • 4 compute nodes (3 NWS, 1 AWS). The NWS-heavy split matches the intent of keeping
  • most workloads on EU-sovereign infrastructure while keeping some capacity on AWS.
  • A WireGuard VPN connecting all seven nodes into one cluster network.
  • Cilium CNI and Longhorn storage installed by Claudie.

Prerequisites

  • A Kubernetes cluster to run Claudie on (the “management cluster”). For testing, a local kind or minikube cluster is enough. For production use something more durable, since Claudie stores state in it.
  • kubectl configured against that cluster.
  • A MyNWS account with quota for at least 4 VMs, 4 floating IPs, and 200 GB of storage in the HetznerNBG4 region.
  • An AWS account with permissions to create EC2 instances, VPCs, and security groups in us-east-2 (or any region you prefer).

Step 1 – Install Claudie

Install cert-manager first. Claudie uses it for its admission webhook:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.3/cert-manager.yaml

Then deploy Claudie itself:

kubectl apply -f https://github.com/berops/claudie/releases/latest/download/claudie.yaml

Give it a minute, then check that the pods are running in the claudie namespace:

kubectl get pods -n claudie
NAME                                 READY   STATUS    RESTARTS   AGE
ansibler-7b5f8c6d49-qvz2w            1/1     Running   0          60s
claudie-operator-59dd646bcf-bjsdr    1/1     Running   0          60s
kube-eleven-bdc799684-xlwws          1/1     Running   0          60s
kuber-7cc7cb797d-bvsrv               1/1     Running   0          60s
manager-69f96bb548-l5wqr             1/1     Running   0          60s
minio-0                              1/1     Running   0          60s
minio-1                              1/1     Running   0          60s
minio-2                              1/1     Running   0          60s
minio-3                              1/1     Running   0          60s
mongodb-858994c5cb-x8w77             1/1     Running   0          60s
nats-0                               2/2     Running   0          60s
nats-1                               2/2     Running   0          60s
nats-2                               2/2     Running   0          60s
terraformer-667b9f4556-dkx4x         1/1     Running   0          60s

All pods should be Running. If some are still pending, wait and re-check.
For more detail (including optional network policies for hardening) see the Claudie Detailed guide.

Step 2 – Create Provider Credentials

You’ll need one set of MyNWS application credentials and one AWS IAM access key.

NETWAYS Web Services (OpenStack Application Credential)

NWS authentication is normally federated through NWS-ID (OIDC). Claudie needs static credentials, so the workflow is two-step: log in with your NWS-ID Project User, then create an OpenStack application credential that Claudie can use directly.

In the NWS Customer Interface, open your OpenStack project and switch on the OpenStack Project User option. Note the username (it looks like <your-id>-openstack-<hash>) and password.

Install the OpenStack CLI (openstack) and authenticate with the Project User:

export OS_AUTH_URL=https://cloud.netways.de:5000/v3/
export OS_IDENTITY_API_VERSION=3
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_USERNAME=<your-project-user>          # e.g. 21133-openstack-427a2
export OS_PROJECT_NAME=<your-project-name>      # often the same string
read -s OS_PASSWORD; export OS_PASSWORD         # read password from clipboard, then Enter

Create the application credential:

openstack application credential create --role member claudie -f shell

id="..."
secret="..."
project_id="..."

Save the id and secret. The secret is shown only once. The project_id from the output is also what you need for the secret. Then look up the domain ID:

openstack project show $(openstack token issue -c project_id -f value) \
    -c domain_id -f value

default

NWS uses the literal string default for the domain ID.

NWS also publishes a downloadable RC file for the application credential(app-cred-claudie-openrc.sh) once it’s created. The file contains OS_APPLICATION_CREDENTIAL_ID and OS_APPLICATION_CREDENTIAL_SECRET, which match the values above.

AWS (IAM Access Key)

Create an IAM user with AmazonEC2FullAccess (or a narrower policy that covers EC2, VPC, and security groups) and note the access key ID and secret access key.

Step 3 – Create Kubernetes Secrets

Create a namespace for your credentials and add both secrets:

kubectl create namespace claudie-secrets

kubectl create secret generic netways-secret \
    --namespace=claudie-secrets \
    --from-literal=authurl='https://cloud.netways.de:5000/v3/' \
    --from-literal=domainid='default' \
    --from-literal=projectid='<your-nws-project-id>' \
    --from-literal=applicationcredentialid='<your-credential-id>' \
    --from-literal=applicationcredentialsecret='<your-credential-secret>'

kubectl create secret generic aws-secret \
    --namespace=claudie-secrets \
    --from-literal=accesskey='<your-aws-access-key-id>' \
    --from-literal=secretkey='<your-aws-secret-access-key>'

Step 4 – Create the Claudie Manifest File

Save the following as netways-aws-cluster.yaml:

apiVersion: claudie.io/v1beta1
kind: InputManifest
metadata:
  name: netways-aws-cluster
  labels:
    app.kubernetes.io/part-of: claudie
spec:
  providers:
    - name: netways-1
      providerType: openstack
      secretRef:
        name: netways-secret
        namespace: claudie-secrets

    - name: aws-1
      providerType: aws
      secretRef:
        name: aws-secret
        namespace: claudie-secrets

  nodePools:
    dynamic:
      - name: nws-ctrl
        providerSpec:
          name: netways-1
          region: HetznerNBG4
          zone: HetznerNBG4
          externalNetworkName: public-network
        count: 1
        serverType: s1.medium
        image: "Ubuntu Noble 24.04 LTS"
        storageDiskSize: 50

      - name: aws-ctrl
        providerSpec:
          name: aws-1
          region: us-east-2
          zone: us-east-2a
        count: 2
        serverType: t3.medium
        image: ami-0ea3c35c5c3284d82
        storageDiskSize: 50

      - name: nws-cmp
        providerSpec:
          name: netways-1
          region: HetznerNBG4
          zone: HetznerNBG4
          externalNetworkName: public-network
        count: 3
        serverType: s1.medium
        image: "Ubuntu Noble 24.04 LTS"
        storageDiskSize: 50

      - name: aws-cmp
        providerSpec:
          name: aws-1
          region: us-east-2
          zone: us-east-2a
        count: 1
        serverType: t3.medium
        image: ami-0ea3c35c5c3284d82
        storageDiskSize: 50

  kubernetes:
    clusters:
      - name: netways-aws-cluster
        version: v1.32.0
        network: 192.168.2.0/24
        pools:
          control:
            - nws-ctrl
            - aws-ctrl
          compute:
            - nws-cmp
            - aws-cmp

Notes on NWS-specific values:

  • serverType: s1.medium is NWS’s general-purpose flavor (4 vCPU, 4 GB RAM, 50 GB local disk). Claudie boots VMs from the image directly, so any s*.*, s2.*, p1.*, or d1.* flavor with non-zero local disk works. List available flavors with openstack flavor list.
  • storageDiskSize: 50 is unrelated to the local disk above. It creates an extra Cinder volume that Claudie attaches to each worker node for Longhorn storage. Controlplane nodes ignore this field.
  • image: "Ubuntu Noble 24.04 LTS" is NWS’s official Ubuntu 24.04 image. Find the current name with openstack image list --public. AWS AMI ami-0ea3c35c5c3284d82 is Ubuntu 24.04 LTS in us-east-2. Look up the right AMI for your region with the Ubuntu AMI locator.

Step 5 – Deploy the Cluster

Apply the manifest:

kubectl apply -f netways-aws-cluster.yaml

inputmanifest.claudie.io/netways-aws-cluster created

Claudie picks it up and starts provisioning. Check progress with:

kubectl get inputmanifest -n claudie

NAME                  STATUS
netways-aws-cluster   IN_PROGRESS

The build moves through four phases: Terraformer (provisioning VMs), Ansibler (configuring nodes, installing WireGuard), KubeEleven (running kubeadm), and Kuber (installing CNI, storage, and post-setup). A 7-node build typically takes 12 to 18 minutes.
When it’s done you’ll see:

kubectl get inputmanifest -n claudie

NAME                  STATUS
netways-aws-cluster   WATCHING_FOR_CHANGES

WATCHING_FOR_CHANGES means Claudie has finished provisioning and is watching for any future edits to the manifest.

Step 6 – Access the Cluster

Claudie writes the generated kubeconfig as a Kubernetes secret in the claudie namespace. Pull it out and point kubectl at it:

kubectl get secrets -n claudie -l claudie.io/output=kubeconfig \
    -o jsonpath='{.items[0].data.kubeconfig}' | base64 -d > netways-aws.kubeconfig
export KUBECONFIG=$PWD/netways-aws.kubeconfig
kubectl get nodes -o wide

NAME                  STATUS   ROLES           AGE   VERSION   INTERNAL-IP   OS-IMAGE
aws-ctrl-xxxxxxx-01   Ready    control-plane   5m    v1.32.0   192.168.2.2   Ubuntu 24.04.1 LTS
aws-ctrl-xxxxxxx-02   Ready    control-plane   5m    v1.32.0   192.168.2.3   Ubuntu 24.04.1 LTS
aws-cmp-yyyyyyy-01    Ready    <none>          3m    v1.32.0   192.168.2.7   Ubuntu 24.04.1 LTS
nws-ctrl-zzzzzzz-01   Ready    control-plane   6m    v1.32.0   192.168.2.1   Ubuntu 24.04.4 LTS
nws-cmp-wwwwwww-01    Ready    <none>          3m    v1.32.0   192.168.2.4   Ubuntu 24.04.4 LTS
nws-cmp-wwwwwww-02    Ready    <none>          3m    v1.32.0   192.168.2.5   Ubuntu 24.04.4 LTS
nws-cmp-wwwwwww-03    Ready    <none>          3m    v1.32.0   192.168.2.6   Ubuntu 24.04.4 LTS

Seven nodes, three control-plane, four workers, all in Ready state. The INTERNAL-IP column shows the WireGuard overlay addresses Claudie assigned from the 192.168.2.0/24 WireGuard network range in your manifest. All inter-node traffic flows encrypted over that network regardless of which cloud the nodes are on.

In a representative test build, the warm cross-cloud round-trip latency between MyNWS in Nuremberg and AWS in Ohio (us-east-2a) measured 219-220 ms over the WireGuard mesh, which is essentially the speed-of-light minimum for transatlantic fiber. Same-region NWS-to-NWS hops are around 1 ms.

Step 7 – Clean Up

Delete the InputManifest to tear down all provisioned infrastructure:

kubectl delete inputmanifest netways-aws-cluster -n claudie

inputmanifest.claudie.io "netways-aws-cluster" deleted

Terraformer destroys VMs, networks, routers, security groups, and floating IPs on both clouds. Teardown usually takes 3 to 5 minutes.

Troubleshooting

  • NWS-ID OIDC keeps prompting for a token. Don’t put OIDC tokens in the secret. Claudie needs static application credentials. Switch on the OpenStack Project User in the NWS Customer Interface, then run openstack application credential create from that session.
  • 401 Unauthorized on apply. The secret is missing one of the five required keys (authurl, domainid, projectid, applicationcredentialid, applicationcredentialsecret) or has stale values from a rotated credential.

What’s Next

Our portfolio

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

How did you like our article?