From 6fbcf75dad034dfe1992622488c10e9dcccdd531 Mon Sep 17 00:00:00 2001 From: Aaron Feledy Date: Wed, 19 Aug 2026 15:58:33 -0500 Subject: [PATCH 1/4] fix: copy bind-mounted SSH keys on Darwin before loading Docker Desktop Mac presents ~/.lando/keys as root, so load-keys.sh skips them with -user www-data. Copy off the mount and chown like Windows. --- CHANGELOG.md | 1 + scripts/load-keys.sh | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 150807a77..27151fd41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }}) +* Fixed SSH keys bind-mounted as root on Docker Desktop Mac being ignored by `load-keys.sh` * Fixed `lando init` treating failed git clones as tar archives ## v3.26.8 - [August 10, 2026](https://github.com/lando/core/releases/tag/v3.26.8) diff --git a/scripts/load-keys.sh b/scripts/load-keys.sh index 87ed22f6b..40f88016d 100755 --- a/scripts/load-keys.sh +++ b/scripts/load-keys.sh @@ -50,8 +50,8 @@ done # We need to do some different magic on Windows because file sharing on windows # does not let you chmod files that are mounted -if [ "$LANDO_HOST_OS" = "win32" ]; then - lando_warn "Creating a special not-mounted key directory for Windows" +if [ "$LANDO_HOST_OS" = "win32" ] || [ "$LANDO_HOST_OS" = "darwin" ]; then + lando_warn "Creating a special not-mounted key directory" mkdir -p /lando_keys for SSH_DIR in "${SSH_DIRS[@]}"; do readarray -t SSH_KEYS < <(find "$SSH_DIR" -maxdepth 1 -not -name 'known_hosts' -type f) From 281573943572f5253f412b1a23b1c35ae4cd91c4 Mon Sep 17 00:00:00 2001 From: Aaron Feledy Date: Wed, 19 Aug 2026 16:17:53 -0500 Subject: [PATCH 2/4] fix: load bind-mounted SSH keys even when owned by root Drop the www-data find filter. If chown/chmod on the mount still leaves the key unreadable, copy just that file to /lando_keys. --- CHANGELOG.md | 2 +- scripts/load-keys.sh | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27151fd41..3190e6ad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }}) -* Fixed SSH keys bind-mounted as root on Docker Desktop Mac being ignored by `load-keys.sh` +* Fixed `load-keys.sh` ignoring SSH keys that Docker bind-mounts as root * Fixed `lando init` treating failed git clones as tar archives ## v3.26.8 - [August 10, 2026](https://github.com/lando/core/releases/tag/v3.26.8) diff --git a/scripts/load-keys.sh b/scripts/load-keys.sh index 40f88016d..502eaf1e0 100755 --- a/scripts/load-keys.sh +++ b/scripts/load-keys.sh @@ -50,8 +50,8 @@ done # We need to do some different magic on Windows because file sharing on windows # does not let you chmod files that are mounted -if [ "$LANDO_HOST_OS" = "win32" ] || [ "$LANDO_HOST_OS" = "darwin" ]; then - lando_warn "Creating a special not-mounted key directory" +if [ "$LANDO_HOST_OS" = "win32" ]; then + lando_warn "Creating a special not-mounted key directory for Windows" mkdir -p /lando_keys for SSH_DIR in "${SSH_DIRS[@]}"; do readarray -t SSH_KEYS < <(find "$SSH_DIR" -maxdepth 1 -not -name 'known_hosts' -type f) @@ -68,7 +68,7 @@ fi # Scan the following directories for keys and filter out non-private keys for SSH_DIR in "${SSH_DIRS[@]}"; do lando_info "Scanning $SSH_DIR for keys..." - readarray -t RAW_LIST < <(find "$SSH_DIR" -maxdepth 1 -not -name '*.pub' -not -name 'known_hosts' -user $LANDO_WEBROOT_USER -type f) + readarray -t RAW_LIST < <(find "$SSH_DIR" -maxdepth 1 -not -name '*.pub' -not -name 'known_hosts' -type f) for RAW_KEY in "${RAW_LIST[@]}"; do SSH_CANDIDATES+=("$RAW_KEY") done @@ -87,8 +87,16 @@ lando_info "Found keys ${SSH_CANDIDATES[*]}" # Go through and validate our candidates for SSH_CANDIDATE in "${SSH_CANDIDATES[@]}"; do lando_debug "Ensuring permissions and ownership of $SSH_CANDIDATE..." - chown -R $LANDO_WEBROOT_USER:$GROUP "$SSH_CANDIDATE" - chmod 600 "$SSH_CANDIDATE" + chown -R $LANDO_WEBROOT_USER:$GROUP "$SSH_CANDIDATE" || true + chmod 600 "$SSH_CANDIDATE" || true + if ! su "$LANDO_WEBROOT_USER" -s /bin/sh -c "test -r \"$SSH_CANDIDATE\""; then + mkdir -p /lando_keys + KEY_COPY="/lando_keys/$(basename "$SSH_CANDIDATE")" + cp -fp "$SSH_CANDIDATE" "$KEY_COPY" + chown -R $LANDO_WEBROOT_USER:$GROUP "$KEY_COPY" + chmod 600 "$KEY_COPY" + SSH_CANDIDATE="$KEY_COPY" + fi lando_debug "Checking whether $SSH_CANDIDATE is a private key..." if grep -l "PRIVATE KEY" "$SSH_CANDIDATE" &> /dev/null; then if command -v ssh-keygen >/dev/null 2>&1; then From 6c8818dcc831593290c4a83acf4b1bc22e24a1d6 Mon Sep 17 00:00:00 2001 From: Aaron Feledy Date: Wed, 19 Aug 2026 16:41:01 -0500 Subject: [PATCH 3/4] fix: copy SSH keys off bind mounts on all platforms Use /lando_keys everywhere, same as Windows. Docker bind mounts cannot be chowned reliably, so IdentityFile always points at the in-container copy. --- CHANGELOG.md | 2 +- examples/keys/README.md | 14 ++++++------- scripts/load-keys.sh | 44 +++++++++++++++++------------------------ 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3190e6ad8..ebd068fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }}) -* Fixed `load-keys.sh` ignoring SSH keys that Docker bind-mounts as root +* Fixed `load-keys.sh` using bind-mounted SSH keys by copying them to `/lando_keys` on all platforms * Fixed `lando init` treating failed git clones as tar archives ## v3.26.8 - [August 10, 2026](https://github.com/lando/core/releases/tag/v3.26.8) diff --git a/examples/keys/README.md b/examples/keys/README.md index da15c6379..9aa857435 100644 --- a/examples/keys/README.md +++ b/examples/keys/README.md @@ -21,10 +21,10 @@ Run the following commands to verify things work as expected ```bash # Should have our keys -lando exec cli -u root -- cat /etc/ssh/ssh_config | grep "/lando/keys/badbadkey" -lando exec cli2 -u root -- cat /etc/ssh/ssh_config | grep "/lando/keys/ppkey" -lando exec cli2 -u root -- cat /etc/ssh/ssh_config | grep "/lando/keys/key with space" -lando exec thesekeys -u root -- cat /etc/ssh/ssh_config | grep "/user/.ssh/mykey3" +lando exec cli -u root -- cat /etc/ssh/ssh_config | grep "/lando_keys/badbadkey" +lando exec cli2 -u root -- cat /etc/ssh/ssh_config | grep "/lando_keys/ppkey" +lando exec cli2 -u root -- cat /etc/ssh/ssh_config | grep "/lando_keys/key with space" +lando exec thesekeys -u root -- cat /etc/ssh/ssh_config | grep "/lando_keys/mykey3" # Should have the LANDO_LOAD_KEYS envvar set correctly by default lando exec cli -- env | grep LANDO_LOAD_KEYS | grep true @@ -40,9 +40,9 @@ lando exec cli -- cat /etc/ssh/ssh_config | grep "/user/.ssh" || echo "$?" | gre cp -f .lando.local.yml.thesekeys .lando.local.yml lando rebuild -y lando exec thesekeys -- env | grep LANDO_LOAD_KEYS | grep "mykey mykey2" -lando exec thesekeys -- cat /etc/ssh/ssh_config | grep "/user/.ssh/mykey" -lando exec thesekeys -- cat /etc/ssh/ssh_config | grep "/user/.ssh/mykey2" -lando exec thesekeys -- cat /etc/ssh/ssh_config | grep "/user/.ssh/mykey3" || echo "$?" | grep 1 +lando exec thesekeys -- cat /etc/ssh/ssh_config | grep "/lando_keys/mykey" +lando exec thesekeys -- cat /etc/ssh/ssh_config | grep "/lando_keys/mykey2" +lando exec thesekeys -- cat /etc/ssh/ssh_config | grep "/lando_keys/mykey3" || echo "$?" | grep 1 ``` ## Destroy tests diff --git a/scripts/load-keys.sh b/scripts/load-keys.sh index 502eaf1e0..4f51a19ca 100755 --- a/scripts/load-keys.sh +++ b/scripts/load-keys.sh @@ -48,22 +48,17 @@ for SSH_DIR in "${SSH_DIRS[@]}"; do mkdir -p "$SSH_DIR" done -# We need to do some different magic on Windows because file sharing on windows -# does not let you chmod files that are mounted -if [ "$LANDO_HOST_OS" = "win32" ]; then - lando_warn "Creating a special not-mounted key directory for Windows" - mkdir -p /lando_keys - for SSH_DIR in "${SSH_DIRS[@]}"; do - readarray -t SSH_KEYS < <(find "$SSH_DIR" -maxdepth 1 -not -name 'known_hosts' -type f) - for SSH_KEY in "${SSH_KEYS[@]}"; do - lando_debug "Copying $SSH_KEY from $SSH_DIR to /lando_keys" - cp -rfp "$SSH_KEY" /lando_keys - done +mkdir -p /lando_keys +for SSH_DIR in "${SSH_DIRS[@]}"; do + readarray -t SSH_KEYS < <(find "$SSH_DIR" -maxdepth 1 -not -name 'known_hosts' -type f) + for SSH_KEY in "${SSH_KEYS[@]}"; do + lando_debug "Copying $SSH_KEY from $SSH_DIR to /lando_keys" + cp -rfp "$SSH_KEY" /lando_keys done - chown -R $LANDO_WEBROOT_USER:$GROUP /lando_keys - SSH_DIRS=( "/lando_keys" ) - SSH_KEYS=() -fi +done +chown -R $LANDO_WEBROOT_USER:$GROUP /lando_keys +SSH_DIRS=( "/lando_keys" ) +SSH_KEYS=() # Scan the following directories for keys and filter out non-private keys for SSH_DIR in "${SSH_DIRS[@]}"; do @@ -78,7 +73,12 @@ done if [ "$LANDO_LOAD_KEYS" != "true" ] && [ "$LANDO_LOAD_KEYS" != "false" ]; then RAW_LIST=($LANDO_LOAD_KEYS) for RAW_KEY in "${RAW_LIST[@]}"; do - SSH_CANDIDATES+=("/user/.ssh/$RAW_KEY") + if [ -f "/user/.ssh/$RAW_KEY" ]; then + cp -fp "/user/.ssh/$RAW_KEY" "/lando_keys/$RAW_KEY" + chown $LANDO_WEBROOT_USER:$GROUP "/lando_keys/$RAW_KEY" + chmod 600 "/lando_keys/$RAW_KEY" + SSH_CANDIDATES+=("/lando_keys/$RAW_KEY") + fi done fi @@ -87,16 +87,8 @@ lando_info "Found keys ${SSH_CANDIDATES[*]}" # Go through and validate our candidates for SSH_CANDIDATE in "${SSH_CANDIDATES[@]}"; do lando_debug "Ensuring permissions and ownership of $SSH_CANDIDATE..." - chown -R $LANDO_WEBROOT_USER:$GROUP "$SSH_CANDIDATE" || true - chmod 600 "$SSH_CANDIDATE" || true - if ! su "$LANDO_WEBROOT_USER" -s /bin/sh -c "test -r \"$SSH_CANDIDATE\""; then - mkdir -p /lando_keys - KEY_COPY="/lando_keys/$(basename "$SSH_CANDIDATE")" - cp -fp "$SSH_CANDIDATE" "$KEY_COPY" - chown -R $LANDO_WEBROOT_USER:$GROUP "$KEY_COPY" - chmod 600 "$KEY_COPY" - SSH_CANDIDATE="$KEY_COPY" - fi + chown -R $LANDO_WEBROOT_USER:$GROUP "$SSH_CANDIDATE" + chmod 600 "$SSH_CANDIDATE" lando_debug "Checking whether $SSH_CANDIDATE is a private key..." if grep -l "PRIVATE KEY" "$SSH_CANDIDATE" &> /dev/null; then if command -v ssh-keygen >/dev/null 2>&1; then From 717770137918c3a59706f4ddaa19939b9be54d77 Mon Sep 17 00:00:00 2001 From: Aaron Feledy Date: Wed, 19 Aug 2026 16:57:24 -0500 Subject: [PATCH 4/4] fix: wipe /lando_keys before recopying SSH keys Stale copies survived restarts and stayed in ssh_config after host keys were removed or deselected. --- scripts/load-keys.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/load-keys.sh b/scripts/load-keys.sh index 4f51a19ca..d89e10733 100755 --- a/scripts/load-keys.sh +++ b/scripts/load-keys.sh @@ -48,6 +48,7 @@ for SSH_DIR in "${SSH_DIRS[@]}"; do mkdir -p "$SSH_DIR" done +rm -rf /lando_keys mkdir -p /lando_keys for SSH_DIR in "${SSH_DIRS[@]}"; do readarray -t SSH_KEYS < <(find "$SSH_DIR" -maxdepth 1 -not -name 'known_hosts' -type f)