Customize sshd with sshd config.d (#525)
* Update OpenSSH server image version and add no penalties configuration * Refactor SSH configuration paths and update test scripts for public key handling * Update Docker Compose volumes to remove read-only flag for shared directory * Remove end-to-end test files and related Docker configuration for CA public cert authentication
This commit is contained in:
parent
3050a85e6e
commit
e96e3f6a3a
16 changed files with 24 additions and 191 deletions
|
|
@ -33,7 +33,7 @@ SSHPIPERD_DEBUG=1 docker-compose up --force-recreate --build -d
|
|||
you will have two sshd:
|
||||
|
||||
* `host-password:2222`: a password only sshd server (user: `user`, password: `pass`)
|
||||
* `host-publickey:2222`: a public key only sshd server (put your public key in `/sshconfig_publickey/.config/authorized_keys`)
|
||||
* `host-publickey:2222`: a public key only sshd server (put your public key in `/publickey_authorized_keys/authorized_keys`)
|
||||
|
||||
more settings: <https://github.com/linuxserver/docker-openssh-server>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
package e2e_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func TestCa(t *testing.T) {
|
||||
|
||||
piperaddr, piperport := nextAvailablePiperAddress()
|
||||
|
||||
piper, _, _, err := runCmd("/sshpiperd/sshpiperd",
|
||||
"-p",
|
||||
piperport,
|
||||
"/sshpiperd/plugins/testcaplugin",
|
||||
"--target",
|
||||
"host-capublickey:2222",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("failed to run sshpiperd: %v", err)
|
||||
}
|
||||
|
||||
defer killCmd(piper)
|
||||
|
||||
waitForEndpointReady(piperaddr)
|
||||
|
||||
randtext := uuid.New().String()
|
||||
targetfie := uuid.New().String()
|
||||
|
||||
c, stdin, stdout, err := runCmd(
|
||||
"ssh",
|
||||
"-v",
|
||||
"-o",
|
||||
"StrictHostKeyChecking=no",
|
||||
"-o",
|
||||
"UserKnownHostsFile=/dev/null",
|
||||
"-p",
|
||||
piperport,
|
||||
"-l",
|
||||
"client_123",
|
||||
"127.0.0.1",
|
||||
fmt.Sprintf(`sh -c "echo -n %v > /shared/%v"`, randtext, targetfie),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("failed to ssh to piper-fixed, %v", err)
|
||||
}
|
||||
|
||||
defer killCmd(c)
|
||||
|
||||
enterPassword(stdin, stdout, "pass")
|
||||
|
||||
time.Sleep(time.Second) // wait for file flush
|
||||
|
||||
checkSharedFileContent(t, targetfie, randtext)
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
FROM debian:bookworm-slim
|
||||
|
||||
EXPOSE 2222
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
COPY ca.pub /etc/ssh/trusted-ca.pub
|
||||
|
||||
RUN apt -y update \
|
||||
&& apt -y install --no-install-recommends --no-install-suggests openssh-server \
|
||||
&& mkdir -p /run/sshd \
|
||||
&& adduser --disabled-password --gecos "" client_123 \
|
||||
&& passwd -d client_123 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY sshd_config /etc/ssh/sshd_config
|
||||
|
||||
ENTRYPOINT ["/usr/sbin/sshd", "-D", "-e", "-f", "/etc/ssh/sshd_config"]
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
Port 2222
|
||||
|
||||
# Trust our CA
|
||||
TrustedUserCAKeys /etc/ssh/trusted-ca.pub
|
||||
|
||||
# Allow pubkey
|
||||
PubkeyAuthentication yes
|
||||
|
||||
# Don't allow passwords
|
||||
PasswordAuthentication no
|
||||
# Don't allow host auth
|
||||
HostbasedAuthentication no
|
||||
# No challenge response
|
||||
ChallengeResponseAuthentication no
|
||||
|
||||
# Allow client to pass locale environment variables
|
||||
AcceptEnv LANG LC_*
|
||||
|
||||
# override default of no subsystems
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
|
||||
# Change this if you have issues
|
||||
LogLevel INFO
|
||||
|
|
@ -2,7 +2,7 @@ version: '3.4'
|
|||
|
||||
services:
|
||||
host-password:
|
||||
image: lscr.io/linuxserver/openssh-server:9.7_p1-r4-ls184
|
||||
image: lscr.io/linuxserver/openssh-server:9.9_p1-r2-ls190
|
||||
environment:
|
||||
- PASSWORD_ACCESS=true
|
||||
- USER_PASSWORD=pass
|
||||
|
|
@ -15,13 +15,13 @@ services:
|
|||
- sshpiper.network=e2e_default
|
||||
volumes:
|
||||
- shared:/shared
|
||||
- sshconfig_password:/config
|
||||
- ./sshdconfig/no_penalties.conf:/config/sshd/sshd_config.d/no_penalties.conf:ro
|
||||
networks:
|
||||
- default
|
||||
- netdistract
|
||||
|
||||
host-publickey:
|
||||
image: lscr.io/linuxserver/openssh-server:9.7_p1-r4-ls184
|
||||
image: lscr.io/linuxserver/openssh-server:9.9_p1-r2-ls190
|
||||
environment:
|
||||
- USER_NAME=user
|
||||
- LOG_STDOUT=true
|
||||
|
|
@ -31,18 +31,20 @@ services:
|
|||
- sshpiper.authorized_keys=c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSU5SR1RIMzI1ckRVcDEydHBsd3VrSG1SOHl0YkM5VFBaODg2Z0NzdHluUDEgdGVzdEB0ZXN0Cg==
|
||||
- sshpiper.private_key=LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFNd0FBQUF0emMyZ3RaVwpReU5UVXhPUUFBQUNEVVJreDk5dWF3MUtkZHJhWmNMcEI1a2ZNcld3dlV6MmZQT29BckxjcHo5UUFBQUpDK2owK1N2bzlQCmtnQUFBQXR6YzJndFpXUXlOVFV4T1FBQUFDRFVSa3g5OXVhdzFLZGRyYVpjTHBCNWtmTXJXd3ZVejJmUE9vQXJMY3B6OVEKQUFBRURjUWdkaDJ6MnIvNmJscTB6aUoxbDZzNklBWDhDKzlRSGZBSDkzMWNITk85UkdUSDMyNXJEVXAxMnRwbHd1a0htUgo4eXRiQzlUUFo4ODZnQ3N0eW5QMUFBQUFEV0p2YkdsaGJrQjFZblZ1ZEhVPQotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K
|
||||
volumes:
|
||||
- shared:/shared
|
||||
- sshconfig_publickey:/config
|
||||
- shared:/shared
|
||||
- publickey_authorized_keys:/config/.ssh/
|
||||
- ./sshdconfig/no_penalties.conf:/config/sshd/sshd_config.d/no_penalties.conf:ro
|
||||
|
||||
host-capublickey:
|
||||
build: ./cahost
|
||||
labels:
|
||||
- sshpiper.port=2222
|
||||
- sshpiper.network=e2e_default
|
||||
image: lscr.io/linuxserver/openssh-server:9.9_p1-r2-ls190
|
||||
environment:
|
||||
- USER_NAME=ca_user
|
||||
- LOG_STDOUT=true
|
||||
volumes:
|
||||
- shared:/shared
|
||||
networks:
|
||||
- default
|
||||
- ./sshdconfig/no_penalties.conf:/config/sshd/sshd_config.d/no_penalties.conf:ro
|
||||
- ./sshdconfig/trusted-ca.conf:/config/sshd/sshd_config.d/trusted-ca.conf:ro
|
||||
- ./sshdconfig/trusted-ca.pub:/config/sshd/trusted-ca.pub:ro
|
||||
|
||||
|
||||
host-k8s-proxy:
|
||||
|
|
@ -95,8 +97,7 @@ services:
|
|||
volumes:
|
||||
- ..:/src
|
||||
- shared:/shared
|
||||
- sshconfig_publickey:/sshconfig_publickey
|
||||
- sshconfig_password:/sshconfig_password
|
||||
- publickey_authorized_keys:/publickey_authorized_keys
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- kubeconfig:/root/.kube:ro
|
||||
command: ["./e2eentry.sh"]
|
||||
|
|
@ -121,9 +122,7 @@ volumes:
|
|||
type: tmpfs
|
||||
device: tmpfs
|
||||
|
||||
sshconfig_publickey:
|
||||
|
||||
sshconfig_password:
|
||||
publickey_authorized_keys:
|
||||
|
||||
kubeconfig:
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ func TestDocker(t *testing.T) {
|
|||
t.Errorf("failed to write to test key: %v", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile("/sshconfig_publickey/.ssh/authorized_keys", []byte(`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINRGTH325rDUp12tplwukHmR8ytbC9TPZ886gCstynP1`), 0400); err != nil {
|
||||
if err := os.WriteFile("/publickey_authorized_keys/authorized_keys", []byte(`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINRGTH325rDUp12tplwukHmR8ytbC9TPZ886gCstynP1`), 0400); err != nil {
|
||||
t.Errorf("failed to write to authorized_keys: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,6 @@ set -x
|
|||
# use entrypoint.sh to generate the ssh_host_ed25519_key
|
||||
PLUGIN="dummy_badname/" bash /sshpiperd/entrypoint.sh 2>/dev/null
|
||||
|
||||
# Create an ssh key pair and then sign the public key with the ca cert
|
||||
chmod 600 cahost/ca
|
||||
ssh-keygen -t ssh-ed25519 -f /etc/ssh/ssh_user -N ""
|
||||
ssh-keygen -s cahost/ca -I ssh_user -n client_123 /etc/ssh/ssh_user.pub
|
||||
|
||||
if [ "${SSHPIPERD_DEBUG}" == "1" ]; then
|
||||
echo "enter debug on hold mode"
|
||||
echo "run [docker exec -ti e2e_testrunner_1 bash] to run to attach"
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ stringData:
|
|||
8ytbC9TPZ886gCstynP1AAAADWJvbGlhbkB1YnVudHU=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
ssh-publickey-cert: |
|
||||
ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMIr7E6Il5fvTpixHHDCszKhlRbzXrB0fnWtxYAYdyVlAAAAINRGTH325rDUp12tplwukHmR8ytbC9TPZ886gCstynP1AAAAAAAAAAAAAAABAAAAC2s4c2UyZV90ZXN0AAAADgAAAApjbGllbnRfMTIzAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIJrzCeQ3a+m8PnA/KUmK+JAfC1tM7SG2gkGmW29nXj1nAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEDICm0JT8fakTkWTRjDtbjjMx0dUrvGvPb+Qzi2592/39CqBj8cEqZAF/DesCJhKmO+hyN4jDxTcKPhPM0y2/sH
|
||||
ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIAf6qglkclnZFuSIlW4ClXcwq+SCYJn7rCYcUpbVVaKrAAAAINRGTH325rDUp12tplwukHmR8ytbC9TPZ886gCstynP1AAAAAAAAAAAAAAABAAAACHNzaF91c2VyAAAACwAAAAdjYV91c2VyAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIJrzCeQ3a+m8PnA/KUmK+JAfC1tM7SG2gkGmW29nXj1nAAAAUwAAAAtzc2gtZWQyNTUxOQAAAECM8mKjWLhTKmhj4sb6r0CVaTz/vO8oy1o/7OzmQyUMMa1ex4mo+HB3RHa5eUGOdcFAJu6O8r6GBEah+O0maH8A
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: host-publickey-key-ca
|
||||
|
|
@ -271,7 +271,7 @@ spec:
|
|||
authorized_keys_file: /files/authorized_keys
|
||||
to:
|
||||
host: host-capublickey:2222
|
||||
username: "client_123"
|
||||
username: "ca_user"
|
||||
private_key_secret:
|
||||
name: host-publickey-key-ca
|
||||
ignore_hostkey: true
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func TestKubernetes(t *testing.T) {
|
|||
t.Errorf("failed to write to test key: %v", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile("/sshconfig_publickey/.ssh/authorized_keys", []byte(`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINRGTH325rDUp12tplwukHmR8ytbC9TPZ886gCstynP1`), 0400); err != nil {
|
||||
if err := os.WriteFile("/publickey_authorized_keys/authorized_keys", []byte(`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINRGTH325rDUp12tplwukHmR8ytbC9TPZ886gCstynP1`), 0400); err != nil {
|
||||
t.Errorf("failed to write to authorized_keys: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
1
e2e/sshdconfig/no_penalties.conf
Normal file
1
e2e/sshdconfig/no_penalties.conf
Normal file
|
|
@ -0,0 +1 @@
|
|||
PerSourcePenaltyExemptList 0.0.0.0/0
|
||||
1
e2e/sshdconfig/trusted-ca.conf
Normal file
1
e2e/sshdconfig/trusted-ca.conf
Normal file
|
|
@ -0,0 +1 @@
|
|||
TrustedUserCAKeys /config/sshd/trusted-ca.pub
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
//go:build full || e2e
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/tg123/sshpiper/libplugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
libplugin.CreateAndRunPluginTemplate(&libplugin.PluginTemplate{
|
||||
Name: "testcaplugin",
|
||||
Usage: "Plugin to test ca public cert auth",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "target",
|
||||
Usage: "target ssh endpoint address",
|
||||
EnvVars: []string{"SSHPIPERD_FIXED_TARGET"},
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {
|
||||
target := c.String("target")
|
||||
|
||||
host, port, err := libplugin.SplitHostPortForSSH(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &libplugin.SshPiperPluginConfig{
|
||||
PasswordCallback: func(conn libplugin.ConnMetadata, password []byte) (*libplugin.Upstream, error) {
|
||||
if string(password) != "pass" {
|
||||
return nil, fmt.Errorf("Password is incorrect")
|
||||
}
|
||||
|
||||
// Load the private key
|
||||
signer, err := os.ReadFile("/etc/ssh/ssh_user")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read private key: %v", err)
|
||||
}
|
||||
|
||||
// Load the public ca certificate
|
||||
capublickey, err := os.ReadFile("/etc/ssh/ssh_user-cert.pub")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read ca cert: %v", err)
|
||||
}
|
||||
|
||||
return &libplugin.Upstream{
|
||||
Host: host,
|
||||
Port: int32(port),
|
||||
IgnoreHostKey: true,
|
||||
Auth: libplugin.CreatePrivateKeyAuth(signer, capublickey),
|
||||
}, nil
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ func TestWorkingDirectory(t *testing.T) {
|
|||
if err := runCmdAndWait(
|
||||
"/bin/cp",
|
||||
path.Join(userdir, "id_rsa.pub"),
|
||||
"/sshconfig_publickey/.ssh/authorized_keys",
|
||||
"/publickey_authorized_keys/authorized_keys",
|
||||
); err != nil {
|
||||
t.Errorf("failed to copy public key: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ func TestYaml(t *testing.T) {
|
|||
if err := runCmdAndWait(
|
||||
"/bin/cp",
|
||||
path.Join(yamldir, "id_rsa.pub"),
|
||||
"/sshconfig_publickey/.ssh/authorized_keys",
|
||||
"/publickey_authorized_keys/authorized_keys",
|
||||
); err != nil {
|
||||
t.Errorf("failed to copy public key: %v", err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue