Skip to content

[staging] use sftp server with gcsfuse for elavon #5019

Merged
jparr merged 4 commits intomainfrom
staging/mov/4420-elavon-sftp
Apr 2, 2026
Merged

[staging] use sftp server with gcsfuse for elavon #5019
jparr merged 4 commits intomainfrom
staging/mov/4420-elavon-sftp

Conversation

@jparr
Copy link
Copy Markdown
Contributor

@jparr jparr commented Apr 2, 2026

Description

This switches elavon to the pattern we developed for enghouse. A dedicated k8 for sftp using gcsfuse to write directly to the bucket

ref: #4420
This will also remove the need for: #4872

Verified connection and that files land.
I am using an new bucket so this is non-destructive.
The new bucket has a slightly different folder structure so will need a change to the parsing code

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 2, 2026

Terraform plan in iac/cal-itp-data-infra-staging/sftp/us/elavon

Plan: 0 to add, 1 to change, 0 to destroy.
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
!~  update in-place

Terraform will perform the following actions:

  # kubernetes_deployment.elavon-sftp will be updated in-place
!~  resource "kubernetes_deployment" "elavon-sftp" {
        id               = "default/elavon-sftp-deployment"
#        (1 unchanged attribute hidden)

!~      spec {
#            (5 unchanged attributes hidden)

!~          template {
!~              spec {
#                    (18 unchanged attributes hidden)

!~                  container {
                        name                       = "sftp-server"
#                        (11 unchanged attributes hidden)

-                       security_context {
-                           allow_privilege_escalation = false -> null
-                           privileged                 = false -> null
-                           read_only_root_filesystem  = false -> null
-                           run_as_non_root            = false -> null
#                            (2 unchanged attributes hidden)

-                           capabilities {
-                               add  = [] -> null
-                               drop = [
-                                   "NET_RAW",
                                ] -> null
                            }
                        }

#                        (6 unchanged blocks hidden)
                    }

-                   security_context {
-                       run_as_non_root        = false -> null
-                       supplemental_groups    = [] -> null
#                        (4 unchanged attributes hidden)

-                       seccomp_profile {
-                           type              = "RuntimeDefault" -> null
#                            (1 unchanged attribute hidden)
                        }
                    }

-                   toleration {
-                       effect             = "NoSchedule" -> null
-                       key                = "kubernetes.io/arch" -> null
-                       operator           = "Equal" -> null
-                       value              = "amd64" -> null
#                        (1 unchanged attribute hidden)
                    }

#                    (3 unchanged blocks hidden)
                }

#                (1 unchanged block hidden)
            }

#            (2 unchanged blocks hidden)
        }

#        (1 unchanged block hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Warning: Deprecated Resource

  with kubernetes_secret.elavon-sftp-hostkeys,
  on kubernetes.tf line 1, in resource "kubernetes_secret" "elavon-sftp-hostkeys":
   1: resource "kubernetes_secret" "elavon-sftp-hostkeys" {

Deprecated; use kubernetes_secret_v1.

(and 4 more similar warnings elsewhere)

📝 Plan generated in Terraform Plan #854

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 2, 2026

Terraform plan in iac/cal-itp-data-infra-staging/sftp/us/enghouse

Plan: 5 to add, 0 to change, 0 to destroy. Changes to Outputs.
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+   create

Terraform will perform the following actions:

  # kubernetes_deployment.enghouse-sftp will be created
+   resource "kubernetes_deployment" "enghouse-sftp" {
+       id               = (known after apply)
+       wait_for_rollout = true

+       metadata {
+           generation       = (known after apply)
+           labels           = {
+               "app" = "enghouse-sftp"
            }
+           name             = "enghouse-sftp-deployment"
+           namespace        = "default"
+           resource_version = (known after apply)
+           uid              = (known after apply)
        }

+       spec {
+           min_ready_seconds         = 0
+           paused                    = false
+           progress_deadline_seconds = 600
+           replicas                  = "1"
+           revision_history_limit    = 10

+           selector {
+               match_labels = {
+                   "app" = "enghouse-sftp"
                }
            }

+           strategy (known after apply)

+           template {
+               metadata {
+                   annotations      = {
+                       "gke-gcsfuse/volumes" = "true"
                    }
+                   generation       = (known after apply)
+                   labels           = {
+                       "app" = "enghouse-sftp"
                    }
+                   name             = (known after apply)
+                   resource_version = (known after apply)
+                   uid              = (known after apply)
                }
+               spec {
+                   automount_service_account_token  = true
+                   dns_policy                       = "ClusterFirst"
+                   enable_service_links             = true
+                   host_ipc                         = false
+                   host_network                     = false
+                   host_pid                         = false
+                   hostname                         = (known after apply)
+                   node_name                        = (known after apply)
+                   restart_policy                   = "Always"
+                   scheduler_name                   = (known after apply)
+                   service_account_name             = "sftp-pod-service-account"
+                   share_process_namespace          = false
+                   termination_grace_period_seconds = 30

+                   container {
+                       command                    = [
+                           "/bin/sh",
+                           "-c",
+                           <<-EOT
                                apk update
                                            apk add openssl openssh openssh-server
                                            addgroup -g 2222 sftpusers
                                            adduser -u 2222 -S -G sftpusers -s /sbin/nologin -D -H enghouse
                                            echo 'enghouse:enghousesftpuserpassword' | chpasswd
                                
                                            mkdir -p /home/enghouse/.ssh
                                            cp /tmp/ssh-keys/authorized_keys /home/enghouse/.ssh/authorized_keys
                                            chmod 700 /home/enghouse/.ssh
                                            chmod 600 /home/enghouse/.ssh/authorized_keys
                                            chown -R enghouse:sftpusers /home/enghouse/.ssh
                                
                                            echo "HostKey /etc/ssh/hostkey/id_rsa" >> /etc/ssh/sshd_config
                                            echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
                                            echo "PermitRootLogin no" >> /etc/ssh/sshd_config
                                            echo "X11Forwarding no" >> /etc/ssh/sshd_config
                                            echo "AllowTcpForwarding no" >> /etc/ssh/sshd_config
                                            echo "Match User enghouse" >> /etc/ssh/sshd_config
                                            echo "Subsystem sftp internal-sftp" >> /etc/ssh/sshd_config
                                            echo "ForceCommand internal-sftp" >> /etc/ssh/sshd_config
                                            echo "ChrootDirectory %h" >> /etc/ssh/sshd_config
                                            /usr/sbin/sshd -D -e
                            EOT,
                        ]
+                       image                      = "alpine"
+                       image_pull_policy          = (known after apply)
+                       name                       = "sftp-server"
+                       restart_policy             = (known after apply)
+                       stdin                      = false
+                       stdin_once                 = false
+                       termination_message_path   = "/dev/termination-log"
+                       termination_message_policy = (known after apply)
+                       tty                        = false

+                       env {
+                           name  = "SFTP_USER"
+                           value = "enghouse"
                        }

+                       port {
+                           container_port = 22
+                           protocol       = "TCP"
                        }

+                       resources (known after apply)

+                       volume_mount {
+                           mount_path        = "/home/enghouse/data"
+                           mount_propagation = "None"
+                           name              = "gcs-volume"
+                           read_only         = false
                        }
+                       volume_mount {
+                           mount_path        = "/etc/ssh/hostkey"
+                           mount_propagation = "None"
+                           name              = "sftp-hostkeys"
+                           read_only         = true
                        }
+                       volume_mount {
+                           mount_path        = "/tmp/ssh-keys"
+                           mount_propagation = "None"
+                           name              = "sftp-authorizedkey"
+                           read_only         = true
                        }
                    }

+                   image_pull_secrets (known after apply)

+                   readiness_gate (known after apply)

+                   volume {
+                       name = "gcs-volume"

+                       csi {
+                           driver            = "gcsfuse.csi.storage.gke.io"
+                           volume_attributes = {
+                               "bucketName"   = "cal-itp-data-infra-staging-enghouse-raw"
+                               "mountOptions" = "uid=2222,gid=2222,file-mode=777,dir-mode=777"
                            }
                        }
                    }
+                   volume {
+                       name = "sftp-hostkeys"

+                       secret {
+                           default_mode = "0600"
+                           secret_name  = "enghouse-sftp-hostkeys"
                        }
                    }
+                   volume {
+                       name = "sftp-authorizedkey"

+                       secret {
+                           default_mode = "0600"
+                           secret_name  = "enghouse-sftp-authorizedkey"
                        }
                    }
                }
            }
        }
    }

  # kubernetes_secret.enghouse-sftp-authorizedkey will be created
+   resource "kubernetes_secret" "enghouse-sftp-authorizedkey" {
+       binary_data_wo                 = (write-only attribute)
+       data                           = (sensitive value)
+       data_wo                        = (write-only attribute)
+       id                             = (known after apply)
+       type                           = "Opaque"
+       wait_for_service_account_token = true

+       metadata {
+           generation       = (known after apply)
+           name             = "enghouse-sftp-authorizedkey"
+           namespace        = "default"
+           resource_version = (known after apply)
+           uid              = (known after apply)
        }
    }

  # kubernetes_secret.enghouse-sftp-hostkeys will be created
+   resource "kubernetes_secret" "enghouse-sftp-hostkeys" {
+       binary_data_wo                 = (write-only attribute)
+       data                           = (sensitive value)
+       data_wo                        = (write-only attribute)
+       id                             = (known after apply)
+       type                           = "Opaque"
+       wait_for_service_account_token = true

+       metadata {
+           generation       = (known after apply)
+           name             = "enghouse-sftp-hostkeys"
+           namespace        = "default"
+           resource_version = (known after apply)
+           uid              = (known after apply)
        }
    }

  # kubernetes_service.enghouse-sftp will be created
+   resource "kubernetes_service" "enghouse-sftp" {
+       id                     = (known after apply)
+       status                 = (known after apply)
+       wait_for_load_balancer = true

+       metadata {
+           generation       = (known after apply)
+           name             = "enghouse-sftp"
+           namespace        = "default"
+           resource_version = (known after apply)
+           uid              = (known after apply)
        }

+       spec {
+           allocate_load_balancer_node_ports = true
+           cluster_ip                        = (known after apply)
+           cluster_ips                       = (known after apply)
+           external_traffic_policy           = (known after apply)
+           health_check_node_port            = (known after apply)
+           internal_traffic_policy           = (known after apply)
+           ip_families                       = (known after apply)
+           ip_family_policy                  = (known after apply)
+           load_balancer_ip                  = "35.236.24.31"
+           publish_not_ready_addresses       = false
+           selector                          = {
+               "app" = "enghouse-sftp"
            }
+           session_affinity                  = "None"
+           type                              = "LoadBalancer"

+           port {
+               node_port   = (known after apply)
+               port        = 22
+               protocol    = "TCP"
+               target_port = "22"
            }

+           session_affinity_config (known after apply)
        }
    }

  # kubernetes_service_account.sftp-pod-service-account will be created
+   resource "kubernetes_service_account" "sftp-pod-service-account" {
+       automount_service_account_token = true
+       default_secret_name             = (known after apply)
+       id                              = (known after apply)

+       metadata {
+           annotations      = {
+               "iam.gke.io/gcp-service-account" = "sftp-pod-service-account@cal-itp-data-infra-staging.iam.gserviceaccount.com"
            }
+           generation       = (known after apply)
+           name             = "sftp-pod-service-account"
+           namespace        = "default"
+           resource_version = (known after apply)
+           uid              = (known after apply)
        }
    }

Plan: 5 to add, 0 to change, 0 to destroy.

Changes to Outputs:
!~  kubernetes_service_enghouse-sftp_load_balancer_status = [
-       {
-           load_balancer = [
-               {
-                   ingress = [
-                       {
-                           hostname = ""
-                           ip       = "35.236.24.31"
                        },
                    ]
                },
            ]
        },
    ] -> (known after apply)

Warning: Deprecated Resource

  with kubernetes_secret.enghouse-sftp-hostkeys,
  on kubernetes.tf line 1, in resource "kubernetes_secret" "enghouse-sftp-hostkeys":
   1: resource "kubernetes_secret" "enghouse-sftp-hostkeys" {

Deprecated; use kubernetes_secret_v1.

(and 4 more similar warnings elsewhere)

📝 Plan generated in Terraform Plan #854

@jparr jparr force-pushed the staging/mov/4420-elavon-sftp branch from 405a8f2 to 0bfee94 Compare April 2, 2026 02:29
@jparr jparr force-pushed the staging/mov/4420-elavon-sftp branch from 0bfee94 to 851ce3e Compare April 2, 2026 17:31
@jparr jparr merged commit bc1b573 into main Apr 2, 2026
10 checks passed
@jparr jparr deleted the staging/mov/4420-elavon-sftp branch April 2, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants