← Back to Index

[!TIP] Ongoing and occasional updates and improvements.

create a sftp pod in openshift

Customer wants to run sftp service in pod, and expose it to the internet. How can we do that? We know that the ingress only support http/https. Here we show several ways to do that.

  1. macvlan
  2. loadbalancer / metalLB
  3. enhance security with kata
  4. service mesh
  5. customize router/haproxy deployment

deploy the ssh pod

ssh runs on port 22, which needs speical privilege. We need to create a security context constraint to allow the pod to run as root user, and add the capability to bind to port 22.

The overall network architecture will be like below, it is simple, we will add more feature and security enhancement later.


        oc new-project llm-demo
        
        mkdir -p $HOME/data/install
        
        # https://access.redhat.com/articles/6973044
        
        # Using the legacy restricted SCC in OCP 4.11+
        
        # do not pay attention to this, it works. :)
        
        # we will create a new scc to allow the pod to run as root user, and add the capability to bind to port 22.
        
        cat << EOF > $HOME/data/install/sftp-scc.yaml
        apiVersion: security.openshift.io/v1
        kind: SecurityContextConstraints
        metadata:
          name: sftp-scc
        allowPrivilegedContainer: false
        allowPrivilegeEscalation: false
        allowHostDirVolumePlugin: false
        allowHostNetwork: false
        allowHostPorts: false
        allowHostPID: false
        allowHostIPC: false
        defaultAddCapabilities:
        
        - CAP_NET_BIND_SERVICE
        - CAP_SYS_CHROOT 
        - CAP_SETGID
        - AUDIT_WRITE
        runAsUser:
          type: RunAsAny
        seLinuxContext:
          type: MustRunAs
        fsGroup:
          type: RunAsAny
        supplementalGroups:
          type: RunAsAny
        volumes:
        
        - configMap
        - downwardAPI
        - emptyDir
        - persistentVolumeClaim
        - projected
        - secret
        EOF
        
        oc apply -f $HOME/data/install/sftp-scc.yaml
        
        # oc delete -f $HOME/data/install/sftp-scc.yaml
        
        # create a new sa, and assign the scc to the sa
        
        oc create sa sftp-sa -n llm-demo
        
        oc adm policy add-scc-to-user sftp-scc -z sftp-sa -n llm-demo
        
        # try to fix the legacy restricted SCC in OCP 4.11+, but it works, forget this
        
        # export VAR_NS='llm-demo'
        
        # oc create rolebinding local:scc:restricted -n $VAR_NS --clusterrole=system:openshift:scc:restricted  --group=system:serviceaccounts:$VAR_NS
        
        # oc delete rolebinding local:scc:restricted -n $VAR_NS
        
        
        # create pvc to hold the sftp upload files
        
        cat << EOF > $HOME/data/install/sftp-pvc.yaml
        apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
          name: sftp-pvc
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
        EOF
        
        oc apply -f $HOME/data/install/sftp-pvc.yaml -n llm-demo
        
        # oc delete -f $HOME/data/install/sftp-pvc.yaml -n llm-demo
        
        # we used to think we need priviledged, but we limit the capability in scc
        
        # so do not need this
        
        # oc label namespace llm-demo pod-security.kubernetes.io/enforce=privileged
        
        # oc label namespace llm-demo pod-security.kubernetes.io/enforce-
        
        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Limit concurrent sessions
            # MaxSessions 2
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: sftp-service
        spec:
          selector:
            app: sftp-pod
          ports:
          - protocol: TCP
            port: 22
            targetPort: 22
        ---
        apiVersion: v1
        kind: Pod
        metadata:
          name: sftp-pod
          labels:
            app: sftp-pod
        spec:
          serviceAccountName: sftp-sa
          containers:
          - name: sftp-container
            image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
            securityContext:
              runAsUser: 0
              capabilities:
                add:
                - CAP_NET_BIND_SERVICE
                - CAP_SYS_CHROOT 
                - CAP_SETGID 
                - AUDIT_WRITE
            volumeMounts:
            - name: sftp-volume
              mountPath: /home/
            - mountPath: /etc/sftp/users.conf
              name: conf
              subPath: users.conf
            - mountPath: /etc/ssh/sshd_config
              name: conf
              subPath: sshd_config
          volumes:
          - name: sftp-volume
            persistentVolumeClaim:
              claimName: sftp-pvc
          - configMap:
              items:
              - key: users.conf
                path: users.conf
              - key: sshd_config
                path: sshd_config
              name: sftp-conf
            name: conf
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        # oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # get the pod ip
        
        oc get pod -o json | jq -r '.items[] | select(.metadata.name | test("^sftp-pod")) | .status.podIP'
        
        # 10.128.2.193
        
        VAR_POD_IP=`oc get pod -o json | jq -r '.items[] | select(.metadata.name | test("^sftp-pod")) | .status.podIP' `
        
        # we create a testing pod, to connect to the sftp pod remotely.
        
        cat << EOF > $HOME/data/install/sftp-test-pod.yaml
        ---
        kind: Pod
        apiVersion: v1
        metadata:
          name: wzh-demo-util
        spec:
          # nodeSelector:
          #   kubernetes.io/hostname: 'worker-01-demo'
          restartPolicy: Always
          containers:
            - name: demo1
              image: >- 
                quay.io/wangzheng422/qimgs:rocky9-test-2024.06.17.v01
              env:
                - name: key
                  value: value
              command: [ "/bin/bash", "-c", "--" ]
              args: [ "tail -f /dev/null" ]
              # imagePullPolicy: Always
        EOF
        
        oc delete -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        oc apply -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        oc rsh -n llm-demo wzh-demo-util
        
        # upload to upload directory, otherwise, it will report error on permission denied
        
        # sftp foo@10.131.0.24
        
        oc exec -it -n llm-demo wzh-demo-util -- sshpass -p pass sftp -o StrictHostKeyChecking=no  foo@$VAR_POD_IP

The sftp container will create user(foo) during startup, and create folder upload in the user’s home directory. If you set the upload folder to 333 chmod -R 333 upload, then the user can upload to the folder, and can create subdir in the folder, but can not list, and read/download file from the upload folder.

expose in macvlan

macvlan is linux kernel feature, which allows you to create virtual network interfaces, which can be attached to a container. This is useful when you want to expose the container to the network directly, without going through the host network stack. There are blogs on redhat website about this:

If using macvlan, the overall network architecture will be like below:


        # create macvlan config
        
        cat << EOF > $HOME/data/install/sftp-macvlan.yaml
        ---
        apiVersion: k8s.cni.cncf.io/v1
        kind: NetworkAttachmentDefinition
        metadata:
          name: sftp-macvlan
        spec:
          config: |- 
            {
              "cniVersion": "0.3.1",
              "name": "sftp-macvlan",
              "type": "macvlan",
              "master": "enp9s0",
              "linkInContainer": false,
              "mode": "bridge",
              "ipam": {
                "type": "static",
                  "addresses": [
                    {
                      "address": "192.168.77.67/24",
                      "_gateway": "1.1.1.1"
                    }
                  ]
              }
            }
        ---
        apiVersion: k8s.cni.cncf.io/v1
        kind: NetworkAttachmentDefinition
        metadata:
          name: sftp-debug-macvlan
        spec:
          config: |- 
            {
              "cniVersion": "0.3.1",
              "name": "sftp-debug-macvlan",
              "type": "macvlan",
              "master": "enp9s0",
              "linkInContainer": false,
              "mode": "bridge",
              "ipam": {
                "type": "static",
                  "addresses": [
                    {
                      "address": "192.168.77.68/24",
                      "_gateway": "1.1.1.1"
                    }
                  ]
              }
            }
        EOF
        
        oc apply -f $HOME/data/install/sftp-macvlan.yaml -n llm-demo
        
        
        
        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        
        ---
        apiVersion: v1
        kind: Pod
        metadata:
          name: sftp-pod
          annotations:
            k8s.v1.cni.cncf.io/networks: sftp-macvlan
        spec:
          serviceAccountName: sftp-sa
          containers:
          - name: sftp-container
            image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
            securityContext:
              runAsUser: 0
              capabilities:
                add:
                - CAP_NET_BIND_SERVICE
                - CAP_SYS_CHROOT 
                - CAP_SETGID
                - AUDIT_WRITE
            volumeMounts:
            - name: sftp-volume
              mountPath: /home/
            - mountPath: /etc/sftp/users.conf
              name: conf
              subPath: users.conf
            - mountPath: /etc/ssh/sshd_config
              name: conf
              subPath: sshd_config
          volumes:
          - name: sftp-volume
            persistentVolumeClaim:
              claimName: sftp-pvc
          - configMap:
              items:
              - key: users.conf
                path: users.conf
              - key: sshd_config
                path: sshd_config
              name: sftp-conf
            name: conf
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # we create a testing pod, to connect to the sftp pod remotely.
        
        cat << EOF > $HOME/data/install/sftp-test-pod.yaml
        ---
        kind: Pod
        apiVersion: v1
        metadata:
          name: wzh-demo-util
          annotations:
            k8s.v1.cni.cncf.io/networks: sftp-debug-macvlan
        spec:
          # nodeSelector:
          #   kubernetes.io/hostname: 'worker-01-demo'
          restartPolicy: Always
          containers:
            - name: demo1
              image: >- 
                quay.io/wangzheng422/qimgs:rocky9-test
              env:
                - name: key
                  value: value
              command: [ "/bin/bash", "-c", "--" ]
              args: [ "tail -f /dev/null" ]
              # imagePullPolicy: Always
        EOF
        
        oc delete -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        oc apply -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        
        oc rsh -n llm-demo wzh-demo-util
        
        # upload to upload directory, otherwise, it will report error on permission denied
        
        # sftp foo@192.168.77.67
        
        # sh-5.1# scp /etc/os-release foo@192.168.77.67:/upload/
        
        # foo@192.168.99.7's password:
        
        # os-release                                                                                                                               100%  507   636.7KB/s   00:00
        
        
        # on helper, on vsphere vm/baremetal node
        
        sftp foo@192.168.77.67
        
        # it turn out on the helper, vsphere platform, we can not connect to the sftp pod
        
        # we need to try on baremental env to see if it works.
        
        # generally, it is macvlan and switch co-working problem.
        
        # Later, yes, we confirmed that on baremetal platform, it works.

expose in ipvlan

macvlan is linux kernel feature, which allows you to create virtual network interfaces, which can be attached to a container. This is useful when you want to expose the container to the network directly, without going through the host network stack. There are blogs on redhat website about this:

If using macvlan, the overall network architecture will be like below:


        # create macvlan config
        
        cat << EOF > $HOME/data/install/sftp-ipvlan.yaml
        ---
        apiVersion: k8s.cni.cncf.io/v1
        kind: NetworkAttachmentDefinition
        metadata:
          name: sftp-ipvlan
        spec:
          config: |- 
            {
              "cniVersion": "0.3.1",
              "name": "sftp-ipvlan",
              "type": "ipvlan",
              "master": "ens224",
              "linkInContainer": false,
              "mode": "l2",
              "ipam": {
                "type": "static",
                  "addresses": [
                    {
                      "address": "192.168.99.67/24",
                      "_gateway": "1.1.1.1"
                    }
                  ]
              }
            }
        ---
        apiVersion: k8s.cni.cncf.io/v1
        kind: NetworkAttachmentDefinition
        metadata:
          name: sftp-debug-ipvlan
        spec:
          config: |- 
            {
              "cniVersion": "0.3.1",
              "name": "sftp-debug-ipvlan",
              "type": "ipvlan",
              "master": "ens224",
              "linkInContainer": false,
              "mode": "l2",
              "ipam": {
                "type": "static",
                  "addresses": [
                    {
                      "address": "192.168.99.68/24",
                      "_gateway": "1.1.1.1"
                    }
                  ]
              }
            }
        EOF
        
        oc apply -f $HOME/data/install/sftp-ipvlan.yaml -n llm-demo
        
        
        
        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        
        ---
        apiVersion: v1
        kind: Pod
        metadata:
          name: sftp-pod
          annotations:
            k8s.v1.cni.cncf.io/networks: sftp-ipvlan
        spec:
          serviceAccountName: sftp-sa
          containers:
          - name: sftp-container
            image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
            securityContext:
              runAsUser: 0
              capabilities:
                add:
                - CAP_NET_BIND_SERVICE
                - CAP_SYS_CHROOT 
                - CAP_SETGID
                - AUDIT_WRITE
            volumeMounts:
            - name: sftp-volume
              mountPath: /home/
            - mountPath: /etc/sftp/users.conf
              name: conf
              subPath: users.conf
            - mountPath: /etc/ssh/sshd_config
              name: conf
              subPath: sshd_config
          volumes:
          - name: sftp-volume
            persistentVolumeClaim:
              claimName: sftp-pvc
          - configMap:
              items:
              - key: users.conf
                path: users.conf
              - key: sshd_config
                path: sshd_config
              name: sftp-conf
            name: conf
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # on helper, on vsphere
        
        sftp foo@192.168.99.67
        
        # using ipvlan is ok, then, macvlan should be ok if vsphere open the mac limitation.

expose ssh service in metalLB

MetaLB needs baremetal environment.

By using metalLB, the network architecture will be like below:

install the metalLB operator, and create a loadbalancer service to expose the ssh service.

Create a single instance of a MetalLB custom resource:

apiVersion: metallb.io/v1beta1
        kind: MetalLB
        metadata:
          name: metallb
          namespace: metallb-system

config ip address pool

apiVersion: metallb.io/v1beta1
        kind: IPAddressPool
        metadata:
          namespace: metallb-system
          name: sftp-pool
          labels: 
            zone: sftp
        spec:
          addresses:
          - 192.168.29.50-192.168.29.53
          autoAssign: false
          avoidBuggyIPs: true

config for L2 advertisement

apiVersion: metallb.io/v1beta1
        kind: L2Advertisement
        metadata:
          name: l2advertisement
          namespace: metallb-system
        spec:
          ipAddressPools:
           - sftp-pool

create the pod using metalLB with service


        
        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: sftp-service
          annotations:
            metallb.universe.tf/address-pool: sftp-pool
        spec:
          selector:
            app: sftp-pod
          ports:
          - protocol: TCP
            port: 22
            targetPort: 22
          type: LoadBalancer
          loadBalancerIP: 192.168.29.50
        ---
        apiVersion: v1
        kind: Pod
        metadata:
          name: sftp-pod
          labels:
            app: sftp-pod
        spec:
          serviceAccountName: sftp-sa
          containers:
          - name: sftp-container
            image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
            securityContext:
              runAsUser: 0
              capabilities:
                add:
                - CAP_NET_BIND_SERVICE
                - CAP_SYS_CHROOT 
                - CAP_SETGID 
                - AUDIT_WRITE
            volumeMounts:
            - name: sftp-volume
              mountPath: /home/
            - mountPath: /etc/sftp/users.conf
              name: conf
              subPath: users.conf
            - mountPath: /etc/ssh/sshd_config
              name: conf
              subPath: sshd_config
          volumes:
          - name: sftp-volume
            persistentVolumeClaim:
              claimName: sftp-pvc
          - configMap:
              items:
              - key: users.conf
                path: users.conf
              - key: sshd_config
                path: sshd_config
              name: sftp-conf
            name: conf
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # on helper
        
        sftp foo@192.168.29.50
        
        # it is ok to sftp

kata to improve security

Kata needs baremetal environment.

By using kata, pod will run in a mini kvm/qemu on rhcos, which will improve the security. We can use kata to run the sftp pod, and expose it to the internet.

The network architecture will be like below:

install sandbox operator

The node installed with kata will reboot once.

in macvlan


        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        
        ---
        apiVersion: v1
        kind: Pod
        metadata:
          name: sftp-pod
          annotations:
            k8s.v1.cni.cncf.io/networks: sftp-macvlan
        spec:
          serviceAccountName: sftp-sa
          runtimeClassName: kata
          containers:
          - name: sftp-container
            image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
            securityContext:
              runAsUser: 0
              capabilities:
                add:
                - CAP_NET_BIND_SERVICE
                - CAP_SYS_CHROOT 
                - CAP_SETGID 
                - AUDIT_WRITE
            volumeMounts:
            - name: sftp-volume
              mountPath: /home/
            - mountPath: /etc/sftp/users.conf
              name: conf
              subPath: users.conf
            - mountPath: /etc/ssh/sshd_config
              name: conf
              subPath: sshd_config
          volumes:
          - name: sftp-volume
            persistentVolumeClaim:
              claimName: sftp-pvc
          - configMap:
              items:
              - key: users.conf
                path: users.conf
              - key: sshd_config
                path: sshd_config
              name: sftp-conf
            name: conf
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # we create a testing pod, to connect to the sftp pod remotely.
        
        cat << EOF > $HOME/data/install/sftp-test-pod.yaml
        ---
        kind: Pod
        apiVersion: v1
        metadata:
          name: wzh-demo-util
          annotations:
            k8s.v1.cni.cncf.io/networks: sftp-debug-macvlan
        spec:
          # nodeSelector:
          #   kubernetes.io/hostname: 'worker-01-demo'
          runtimeClassName: kata
          restartPolicy: Always
          containers:
            - name: demo1
              image: >- 
                quay.io/wangzheng422/qimgs:rocky9-test
              env:
                - name: key
                  value: value
              command: [ "/bin/bash", "-c", "--" ]
              args: [ "tail -f /dev/null" ]
              # imagePullPolicy: Always
        EOF
        
        oc delete -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        oc apply -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        
        oc rsh -n llm-demo wzh-demo-util
        
        # upload to upload directory, otherwise, it will report error on permission denied
        
        # sftp foo@192.168.77.67
        
        # sh-5.1# scp /etc/os-release foo@192.168.77.67:/upload/
        
        # foo@192.168.99.7's password:
        
        # os-release                                                                                                                               100%  507   636.7KB/s   00:00
        
        
        # on helper, on vsphere vm/baremetal node
        
        sftp foo@192.168.77.67
        
        # it turn out on the helper, vsphere platform, we can not connect to the sftp pod
        
        # we need to try on baremental env to see if it works.
        
        # generally, it is macvlan and switch co-working problem.
        
        # Later, yes, we confirmed that on baremetal platform, it works.
        

in ipvlan


        
        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        
        ---
        apiVersion: v1
        kind: Pod
        metadata:
          name: sftp-pod
          annotations:
            k8s.v1.cni.cncf.io/networks: sftp-ipvlan
        spec:
          serviceAccountName: sftp-sa
          runtimeClassName: kata
          containers:
          - name: sftp-container
            image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
            securityContext:
              runAsUser: 0
              capabilities:
                add:
                - CAP_NET_BIND_SERVICE
                - CAP_SYS_CHROOT 
                - CAP_SETGID
                - AUDIT_WRITE
            volumeMounts:
            - name: sftp-volume
              mountPath: /home/
            - mountPath: /etc/sftp/users.conf
              name: conf
              subPath: users.conf
            - mountPath: /etc/ssh/sshd_config
              name: conf
              subPath: sshd_config
          volumes:
          - name: sftp-volume
            persistentVolumeClaim:
              claimName: sftp-pvc
          - configMap:
              items:
              - key: users.conf
                path: users.conf
              - key: sshd_config
                path: sshd_config
              name: sftp-conf
            name: conf
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # on helper, on vsphere
        
        sftp foo@192.168.99.67
        
        # using ipvlan is ok, then, macvlan should be ok if vsphere open the mac limitation.
        
        

in metalLB


        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: sftp-service
          annotations:
            metallb.universe.tf/address-pool: sftp-pool
        spec:
          selector:
            app: sftp-pod
          ports:
          - protocol: TCP
            port: 22
            targetPort: 22
          type: LoadBalancer
          loadBalancerIP: 192.168.29.50
        ---
        apiVersion: v1
        kind: Pod
        metadata:
          name: sftp-pod
          labels:
            app: sftp-pod
        spec:
          serviceAccountName: sftp-sa
          runtimeClassName: kata
          containers:
          - name: sftp-container
            image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
            securityContext:
              runAsUser: 0
              capabilities:
                add:
                - CAP_NET_BIND_SERVICE
                - CAP_SYS_CHROOT 
                - CAP_SETGID 
                - AUDIT_WRITE
            volumeMounts:
            - name: sftp-volume
              mountPath: /home/
            - mountPath: /etc/sftp/users.conf
              name: conf
              subPath: users.conf
            - mountPath: /etc/ssh/sshd_config
              name: conf
              subPath: sshd_config
          volumes:
          - name: sftp-volume
            persistentVolumeClaim:
              claimName: sftp-pvc
          - configMap:
              items:
              - key: users.conf
                path: users.conf
              - key: sshd_config
                path: sshd_config
              name: sftp-conf
            name: conf
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # on helper
        
        sftp foo@192.168.29.50
        
        # it is ok to sftp
        
        

sftp deny download, only upload allowed.


        apt-get update
        apt-get install acl
        
        chmod -R 330 /home/foo/upload
        
        setfacl -m d:u::wx,d:g::wx,d:o::- /home/foo/upload

auto delete upload file

For demo purpose, we need to save the storage space, so we need to delete the uploaded file automatically.


        oc new-project llm-demo
        
        mkdir -p $HOME/data/install
        
        # https://access.redhat.com/articles/6973044
        
        # Using the legacy restricted SCC in OCP 4.11+
        
        # do not pay attention to this, it works. :)
        
        # we will create a new scc to allow the pod to run as root user, and add the capability to bind to port 22.
        
        cat << EOF > $HOME/data/install/sftp-scc.yaml
        apiVersion: security.openshift.io/v1
        kind: SecurityContextConstraints
        metadata:
          name: sftp-scc
        allowPrivilegedContainer: false
        allowPrivilegeEscalation: false
        allowHostDirVolumePlugin: false
        allowHostNetwork: false
        allowHostPorts: false
        allowHostPID: false
        allowHostIPC: false
        defaultAddCapabilities:
        
        - CAP_NET_BIND_SERVICE
        - CAP_SYS_CHROOT 
        - CAP_SETGID
        - AUDIT_WRITE
        runAsUser:
          type: RunAsAny
        seLinuxContext:
          type: MustRunAs
        fsGroup:
          type: RunAsAny
        supplementalGroups:
          type: RunAsAny
        volumes:
        
        - configMap
        - downwardAPI
        - emptyDir
        - persistentVolumeClaim
        - projected
        - secret
        EOF
        
        oc apply -f $HOME/data/install/sftp-scc.yaml
        
        # oc delete -f $HOME/data/install/sftp-scc.yaml
        
        # create a new sa, and assign the scc to the sa
        
        oc create sa sftp-sa -n llm-demo
        
        oc adm policy add-scc-to-user sftp-scc -z sftp-sa -n llm-demo
        
        # try to fix the legacy restricted SCC in OCP 4.11+, but it works, forget this
        
        # export VAR_NS='llm-demo'
        
        # oc create rolebinding local:scc:restricted -n $VAR_NS --clusterrole=system:openshift:scc:restricted  --group=system:serviceaccounts:$VAR_NS
        
        # oc delete rolebinding local:scc:restricted -n $VAR_NS
        
        
        # create pvc to hold the sftp upload files
        
        cat << EOF > $HOME/data/install/sftp-pvc.yaml
        apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
          name: sftp-pvc
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 20Gi
        EOF
        
        oc delete -f $HOME/data/install/sftp-pvc.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pvc.yaml -n llm-demo
        
        # oc delete -f $HOME/data/install/sftp-pvc.yaml -n llm-demo
        
        # we used to think we need priviledged, but we limit the capability in scc
        
        # so do not need this
        
        # oc label namespace llm-demo pod-security.kubernetes.io/enforce=privileged
        
        # oc label namespace llm-demo pod-security.kubernetes.io/enforce-
        
        
        # we use a startup script to get pod information
        
        # and store it to log dir, so admin can know the pod information
        
        cat << 'EOF' > ${HOME}/data/install/auto-remove.sh
        #!/bin/bash
        
        echo "try to remove hprof files"
        
        # Loop indefinitely
        
        while true; do
          # Find files in the directory that were last modified 1 minute ago or more
          # and remove them
          # echo "try to remove hprof files"
        
          find "$LOCAL_DIR" -type f -name "*.hprof" -mmin +1 -exec sh -c 'echo "Removing {}"; rm -f {}' \;
        
          sleep 5
        
        done
        EOF
        
        oc delete configmap sftp-script-configmap -n llm-demo
        
        # inject the script into a configmap
        
        oc create configmap sftp-script-configmap \
          --from-file=${HOME}/data/install/auto-remove.sh \
          -n llm-demo
        
        
        # create the sftp pod
        
        # first, create the configmap, which contains the sshd_config and users.conf
        
        # but this should not need, because the image has the default config
        
        # we used to hack for the pod not running, but it is not necessary right now.
        
        cat << EOF > $HOME/data/install/sftp-pod.yaml
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: sftp-conf
        data:
          sshd_config: |
            # Secure defaults
            # See: https://stribika.github.io/2015/01/04/secure-secure-shell.html
            Protocol 2
            HostKey /etc/ssh/ssh_host_ed25519_key
            HostKey /etc/ssh/ssh_host_rsa_key
        
            # Faster connection
            # See: https://github.com/atmoz/sftp/issues/11
            UseDNS no
        
            # Limited access
            PermitRootLogin no
            X11Forwarding no
            AllowTcpForwarding no
        
            # Force sftp and chroot jail
            Subsystem sftp internal-sftp
            ForceCommand internal-sftp
            ChrootDirectory %h
        
            # Limit concurrent sessions
            # MaxSessions 2
        
            # Enable this for more logs
            # LogLevel VERBOSE
          users.conf: |
            foo:pass:1001::upload
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: sftp-service
        spec:
          selector:
            app: sftp-pod
          ports:
          - protocol: TCP
            port: 22
            targetPort: 22
        ---
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: sftp-pod
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: sftp-pod
          template:
            replicas: 1
            metadata:
              labels:
                app: sftp-pod
            spec:
              serviceAccountName: sftp-sa
              containers:
              - name: sftp-container
                image: quay.io/wangzheng422/qimgs:sftp-ubi9-2024.06.20
                securityContext:
                  runAsUser: 0
                  capabilities:
                    add:
                    - CAP_NET_BIND_SERVICE
                    - CAP_SYS_CHROOT 
                    - CAP_SETGID 
                    - AUDIT_WRITE
                volumeMounts:
                - name: sftp-volume
                  mountPath: /home/
                - mountPath: /etc/sftp/users.conf
                  name: conf
                  subPath: users.conf
                - mountPath: /etc/ssh/sshd_config
                  name: conf
                  subPath: sshd_config
              - name: auto-remove
                # the image used here is not optimized for rpms installed, it is just for demo.
                image: quay.io/wangzheng422/qimgs:rocky9-test-2024.06.17.v01
                command: ['bash', '/wzh-scripts/auto-remove.sh']
                volumeMounts:
                - name: wzh-script-volume
                  mountPath: /wzh-scripts
                - name: sftp-volume
                  mountPath: /home/
                env:
                - name: LOCAL_DIR
                  value: /home/
              volumes:
              - name: sftp-volume
                persistentVolumeClaim:
                  claimName: sftp-pvc
              - configMap:
                  items:
                  - key: users.conf
                    path: users.conf
                  - key: sshd_config
                    path: sshd_config
                  name: sftp-conf
                name: conf
              - name: wzh-script-volume
                configMap:
                  name: sftp-script-configmap
        EOF
        
        oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        oc apply -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        # oc delete -f $HOME/data/install/sftp-pod.yaml -n llm-demo
        
        # for lvm pv, we fix the permission issue on /home
        
        # oc rsh -n llm-demo sftp-pod
        
        oc exec -it -n llm-demo sftp-pod -- chown root:root /home
        oc exec -it -n llm-demo sftp-pod -- chmod 755 /home
        
        
        # check the files
        
        # oc exec -it -n llm-demo sftp-pod -- ls -Rlh /home
        
        # Set the namespace and deployment name
        
        NAMESPACE="llm-demo"
        DEPLOYMENT_NAME="sftp-pod"
        
        # Get the label selector for the deployment
        
        LABEL_SELECTOR=$(oc get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.spec.selector.matchLabels}'| jq -r 'to_entries | map("\(.key)=\(.value)") | join(",")')
        
        # Find pods by label selector
        
        PODS=$(oc get pods -n $NAMESPACE -l $LABEL_SELECTOR -o name)
        
        # Loop through each pod and run the command
        
        for POD in $PODS; do
            echo "Executing on $POD"
            oc exec -it -n $NAMESPACE $POD -- ls -Rlh /home
        done
        
        # remove all the switch files
        
        oc exec -it -n llm-demo sftp-pod -- find /home -type f -name "upload.switch" -exec rm -f {} \;
        
        # get the pod ip
        
        oc get pod -o json | jq -r '.items[] | select(.metadata.name | test("^sftp-pod")) | .status.podIP'
        
        # 10.131.0.180
        
        VAR_POD_IP=`oc get pod -o json | jq -r '.items[] | select(.metadata.name | test("^sftp-pod")) | .status.podIP' `
        
        # we create a testing pod, to connect to the sftp pod remotely.
        
        cat << EOF > $HOME/data/install/sftp-test-pod.yaml
        ---
        kind: Pod
        apiVersion: v1
        metadata:
          name: wzh-demo-util
        spec:
          # nodeSelector:
          #   kubernetes.io/hostname: 'worker-01-demo'
          restartPolicy: Always
          containers:
            - name: demo1
              image: >- 
                quay.io/wangzheng422/qimgs:rocky9-test-2024.06.17.v01
              env:
                - name: key
                  value: value
              command: [ "/bin/bash", "-c", "--" ]
              args: [ "tail -f /dev/null" ]
              # imagePullPolicy: Always
        EOF
        
        oc delete -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        oc apply -f ${HOME}/data/install/sftp-test-pod.yaml -n llm-demo
        
        oc rsh -n llm-demo wzh-demo-util
        
        # upload to upload directory, otherwise, it will report error on permission denied
        
        # sftp foo@10.131.0.24
        
        oc exec -it -n llm-demo wzh-demo-util -- sshpass -p pass sftp -o StrictHostKeyChecking=no  foo@$VAR_POD_IP
        
        
        oc exec -it -n llm-demo wzh-demo-util -- sshpass -p pass scp -o StrictHostKeyChecking=no /etc/os-release  foo@$VAR_POD_IP:upload/
        

end