Skip to content

Secure Shell (SSH)

Access your Pod on external networks through SSH on a randomly assigned port at nodeport.icedc.se.

Example

In this example, we create a

  1. Pod with Alpine Linux and expose SSH port 22.
  2. Service that maps this port to a random NodePort.
  3. Secret that contains the authorized_key using our id_rsa.pub.

When the Pod starts

  1. Install openssh-server and generate a random host key.
  2. Copy the Secret into /root/.ssh/authorized_keys and set permissions
  3. Start sshd while logging to standard output.
ssh-example.yaml
apiVersion: v1
kind: Pod
metadata:
  name: testpod
  labels:
    app: testapp
spec:
  containers:
    - name: testssh
      image: alpine
      ports:
        - name: ssh-port
          containerPort: 22
      command:
        - sh
        - -c
        - |
          /bin/sh <<'EOF'
          apk update && apk add openssh-server
          ssh-keygen -f /etc/ssh/ssh_host_rsa_key -C '' -N '' -t rsa
          mkdir -p /root/.ssh
          cp /config/authorized_keys /root/.ssh/ 
          chmod -R og-rwx /root/.ssh  
          /usr/sbin/sshd -eD
          EOF
      volumeMounts:
        - name: config-keys
          mountPath: /config
      resources:
        requests:
          memory: "64Mi"
          cpu: "100m"
        limits:
          memory: "64Mi"
  volumes:
    - name: config-keys
      secret:
        secretName: testpod-keys
        defaultMode: 0400
---
apiVersion: v1
kind: Service
metadata:
  name: testpod-ssh
spec:
  selector:
    app: testapp
  type: NodePort
  ports:
    - name: ssh
      port: 22
      targetPort: ssh-port
---
apiVersion: v1
kind: Secret
metadata:
  name: testpod-keys
type: Opaque
stringData:
  authorized_keys: |
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtcmW6eVcIFSmWOD...

Create the objects

kubectl create -f ssh-example.yaml

List services in the namespace

kubectl get svc
NAME          TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
testpod-ssh   NodePort   10.43.199.42   <none>        22:32319/TCP   9s

Here, 32319 is the external port. You can now log in with

ssh -p 32319 root@nodeport.icedc.se
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <https://wiki.alpinelinux.org/>.

You can setup the system with the command: setup-alpine

You may change this message by editing /etc/motd.

testpod:~# 

SSH configuration

Following are some tips when working with Kubernetes containers over SSH.

Read NodePort number into an environment variable

To automatically parse the NodePort number for your namespace, you can use kubectl.

Store the name of your namespace in the environment variable $NS.

NS=johank-myfirstns

Read the NodePort number into the variable $NODEPORT.

NODEPORT=$(kubectl get svc -n $NS -o go-template='{{range .items}}{{range.spec.ports}}{{if .nodePort}}{{.nodePort}}{{"\n"}}{{end}}{{end}}{{end}}');

You can then use $NODEPORT in your SSH command.

ssh -p $NODEPORT root@nodeport.icedc.se

Local SSH configuration

Store the SSH configuration for nodeport.icedc.se in ~/.ssh/config.

~/.ssh/config.d/nodeport
Host nodeport.icedc.se
    User root
    Port 32293
    HostName nodeport.icedc.se
    StrictHostKeyChecking no
    LogLevel=quiet
    UserKnownHostsFile=/dev/null

The last three lines are optional. They disable the warning IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! when the host key in ~/.ssh/known_hosts does not match the host key of the server. Since Kubernetes pods may be restarted at any time, this may become annoying.

Scripted update of NodePort in SSH configuration

You can split your ~/.ssh/config into multiple files in the folder ~/.ssh/config.d/.

$ ls .ssh/config.d/
home  nodeport  ecc

Update the Port line in ~/.ssh/config.d/nodeport with

sed -i 's/\(Port \).*/\1'$NODEPORT'/g' ~/.ssh/config.d/nodeport

Then recombine all files into a single ~/.ssh/config with

cat ~/.ssh/config.d/* >! ~/.ssh/config