Compare commits

...

55 commits

Author SHA1 Message Date
Matthias Pigulla
2d8d48e56a Run only SSH 2021-03-03 07:38:23 +00:00
Matthias Pigulla
5a354bf325 Run windows only 2021-03-02 20:43:23 +00:00
Matthias Pigulla
6458b79183 Use another action for debugging 2021-03-02 20:33:48 +00:00
Matthias Pigulla
873b13078f Run tmate directly 2021-03-02 20:29:34 +00:00
Matthias Pigulla
3fc2400425 Debug 2021-03-02 20:28:33 +00:00
Matthias Pigulla
3715bc571d Use IdentitiesOnly=yes, because on Windows the wrong key was sent first (_but_: taken from the Agent) 2021-03-02 18:30:41 +00:00
Matthias Pigulla
71155bedbe Poke at things with a stick 2021-03-02 18:27:44 +00:00
Matthias Pigulla
10fed90131 Test whether we're using the wrong ssh client 2021-03-02 17:38:18 +00:00
Matthias Pigulla
d3770df27e Use IdentitiesOnly=yes always 2021-03-02 16:13:48 +00:00
Matthias Pigulla
7667967a0a Show loaded keys 2021-03-02 16:13:26 +00:00
Matthias Pigulla
c77dd5afd7 ... 2021-03-02 16:11:15 +00:00
Matthias Pigulla
a4b2891e37 Set DISPLAY to circumvent read_passphrase (?) 2021-03-02 16:07:52 +00:00
Matthias Pigulla
7cabdfc0cc Print cwd 2021-03-02 16:03:44 +00:00
Matthias Pigulla
da67187c5e use printenv (powershell?) 2021-03-02 16:03:17 +00:00
Matthias Pigulla
64510141b4 Print env 2021-03-02 16:01:37 +00:00
Matthias Pigulla
8cdc63104f Create /dev/tty on D: also 2021-03-02 15:55:31 +00:00
Matthias Pigulla
e0d767fd8e Make sure file creation works 2021-03-02 15:40:01 +00:00
Matthias Pigulla
feedd601c5 Fix Windows file path to use backslashes 2021-03-02 15:31:47 +00:00
Matthias Pigulla
e35dbcbae9 Work around another bug in OpenSSH on Windows 2021-03-02 15:29:19 +00:00
Matthias Pigulla
cbf6c2b3c2 Also try AddKeysToAgent=yes 2021-03-01 11:31:50 +00:00
Matthias Pigulla
2bcaae34da Avoid using a separate shell 2021-03-01 11:16:21 +00:00
Matthias Pigulla
f03f6e3358 Debug SSH_AUTH_SOCK 2021-03-01 11:05:21 +00:00
Matthias Pigulla
7d6e731f4a Use SSH_AUTH_SOCK in following ssh-add invocations 2021-03-01 10:59:34 +00:00
Matthias Pigulla
88bcf9af86 Use IdentitiesOnly=no 2021-03-01 10:53:18 +00:00
Matthias Pigulla
02a6899abb Keep output 2021-03-01 10:50:07 +00:00
Matthias Pigulla
5f971b8d4f Add askpass.c source code 2021-03-01 10:46:52 +00:00
Matthias Pigulla
ab7e1e8f32 Trigger workflows 2021-03-01 09:51:34 +00:00
Matthias Pigulla
7f61bbc4ae Use different ssh-add command for Windows/!Windows 2021-03-01 09:41:11 +00:00
Matthias Pigulla
2bde568a83 Trigger Actions 2021-03-01 09:35:32 +00:00
Matthias Pigulla
93c9b23aa1 Empty commit 2021-03-01 09:27:02 +00:00
Matthias Pigulla
1606d19f15 Preserve process.env so the PATH (and possibly other) vars are availabe 2021-03-01 09:24:06 +00:00
Matthias Pigulla
8addcca750 Debug with ngrok/ssh 2021-03-01 08:47:08 +00:00
Matthias Pigulla
166067472e More debugging 2021-03-01 08:35:43 +00:00
Matthias Pigulla
f78cad1cc7 Try to output ssh-add failure 2021-03-01 08:19:03 +00:00
Matthias Pigulla
ccd95b931d Use execSync instead of execFileSync 2021-03-01 08:16:26 +00:00
Matthias Pigulla
637f9c791e Fix execFileSync call 2021-03-01 08:15:05 +00:00
Matthias Pigulla
18f53866de Use absolute path for askpass.exe 2021-03-01 08:13:10 +00:00
Matthias Pigulla
c91aeeb123 Fake askpass 2021-03-01 08:09:30 +00:00
Matthias Pigulla
25b1b5d69f Compile Hello World on Windows 2021-03-01 07:33:08 +00:00
Matthias Pigulla
9406a51fa5 Remove stdio: 'inherit' 2021-02-28 16:07:26 +00:00
Matthias Pigulla
ef63fdb1df Fix syntax 2021-02-28 16:04:53 +00:00
Matthias Pigulla
7fc4d80a06 Debug output 2021-02-28 15:58:23 +00:00
Matthias Pigulla
9b7e80db62 Use exec 2021-02-28 15:55:23 +00:00
Matthias Pigulla
4d491fcb08 Fix ssh-add syntax (?) 2021-02-28 15:53:33 +00:00
Matthias Pigulla
1676d1f2a9 Use an askpass wrapper 2021-02-28 15:52:09 +00:00
Matthias Pigulla
3702096734 Try writing keys to disk and encrypting them 2021-02-28 15:05:09 +00:00
Matthias Pigulla
253819f283 Start another agent 2021-02-27 20:00:21 +00:00
Matthias Pigulla
231e859720 Re-add key to agent after setting passphrase 2021-02-27 19:54:52 +00:00
Matthias Pigulla
5e4ad4bcc8 Explicitly disable IdentitiesOnly 2021-02-27 18:25:44 +00:00
Matthias Pigulla
c56b9c4c81 Encrypt key on disk 2021-02-27 18:13:12 +00:00
Matthias Pigulla
d7353c1718 Write private key to file (does this work on Windows?) 2021-02-27 18:10:53 +00:00
Matthias Pigulla
bcd9c12595 Print key file name 2021-02-27 11:05:12 +00:00
Matthias Pigulla
ab4471f51e Remove steps that cause noise during debugging 2021-02-27 11:03:19 +00:00
Matthias Pigulla
05624726bc Remove "IdentitiesOnly" 2021-02-27 11:00:51 +00:00
Matthias Pigulla
2a421d8dab
Debug deployment keys on Windows 2021-02-26 22:22:35 +01:00
5 changed files with 192 additions and 115 deletions

View file

@ -1,60 +1,45 @@
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
single_key_demo:
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Setup key
uses: ./
with:
ssh-private-key: |
${{ secrets.DEMO_KEY }}
${{ secrets.DEMO_KEY_2 }}
multiple_keys_demo:
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Setup key
uses: ./
with:
ssh-private-key: ${{ secrets.DEMO_KEY }}
docker_demo:
runs-on: ubuntu-latest
container:
image: ubuntu:latest
steps:
- uses: actions/checkout@v2
- run: apt update && apt install -y openssh-client
- name: Setup key
uses: ./
with:
ssh-private-key: |
${{ secrets.DEMO_KEY }}
${{ secrets.DEMO_KEY_2 }}
deployment_keys_demo: deployment_keys_demo:
runs-on: ubuntu-latest env:
GIT_SSH_COMMAND: ssh -v
strategy:
fail-fast: false
matrix:
os: [windows-latest]
runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Setup key # - name: Setup key
uses: ./ # uses: ./
# with:
# ssh-private-key: |
# ${{ secrets.MPDUDE_TEST_1_DEPLOY_KEY }}
# ${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }}
# - run: |
# cat ~/.ssh/config
# ssh-add -l
# C:/Windows/System32/OpenSSH/ssh.exe -v git@key-2 'echo octocat'
- name: Start SSH session
uses: luchihoratiu/debug-via-ssh@main
with: with:
ssh-private-key: | NGROK_AUTH_TOKEN: ${{ secrets.NGROK_AUTH_TOKEN }}
${{ secrets.MPDUDE_TEST_1_DEPLOY_KEY }} SSH_PASS: ${{ secrets.SSH_PASS }}
${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }}
- run: | # git clone git@github.com:mpdude/test-2.git test-2-git
git clone https://github.com/mpdude/test-1.git test-1-http # ls -alh ~/.ssh
git clone git@github.com:mpdude/test-1.git test-1-git # git clone https://github.com/mpdude/test-1.git test-1-http
git clone ssh://git@github.com/mpdude/test-1.git test-1-git-ssh # git clone git@github.com:mpdude/test-1.git test-1-git
git clone https://github.com/mpdude/test-2.git test-2-http # git clone ssh://git@github.com/mpdude/test-1.git test-1-git-ssh
git clone git@github.com:mpdude/test-2.git test-2-git # git clone https://github.com/mpdude/test-2.git test-2-http
git clone ssh://git@github.com/mpdude/test-2.git test-2-git-ssh
# git clone ssh://git@github.com/mpdude/test-2.git test-2-git-ssh
# cat > ~/.ssh/5965bf89ab6e2900262e3f6802dfb4d65cb0de539d0fbb97d381e7130a4ba7e9 <<< "${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }}"
# ssh-keygen -p -f ~/.ssh/5965bf89ab6e2900262e3f6802dfb4d65cb0de539d0fbb97d381e7130a4ba7e9 -N secret-passphrase
# eval `ssh-agent`
# echo "secret-passphrase" | ssh-add ~/.ssh/5965bf89ab6e2900262e3f6802dfb4d65cb0de539d0fbb97d381e7130a4ba7e9
# ssh-add -L
# git clone git@github.com:mpdude/test-2.git test-2-git
# shell: bash

24
askpass.c Normal file
View file

@ -0,0 +1,24 @@
/*
ssh-add on Windows (probably part of the source at https://github.com/PowerShell/openssh-portable)
does not/can not read the passphrase from stdin.
However, when the DISPLAY env var is set and ssh-add is not run from a terminal (however it tests
that), it will run the executable pointed to by SSH_ASKPASS in a subprocess and read the passphrase
from that subprocess' stdout.
This program can be used as the SSH_ASKPASS implementation. It will return the passphrase set
in the SSH_PASS env variable.
To cross-compile from Ubuntu, I installed the `mingw-w64` package and ran
$ x86_64-w64-mingw32-gcc askpass.c -static -o askpass.exe
*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
printf("%s\n", getenv("SSH_PASS"));
return 0;
}

BIN
askpass.exe Executable file

Binary file not shown.

96
dist/index.js vendored
View file

@ -119,7 +119,8 @@ const core = __webpack_require__(470);
const child_process = __webpack_require__(129); const child_process = __webpack_require__(129);
const fs = __webpack_require__(747); const fs = __webpack_require__(747);
const os = __webpack_require__(87); const os = __webpack_require__(87);
const crypto = __webpack_require__(417); const token = __webpack_require__(417).randomBytes(64).toString('hex');
const isWindows = (process.env['OS'] == 'Windows_NT');
try { try {
const privateKey = core.getInput('ssh-private-key'); const privateKey = core.getInput('ssh-private-key');
@ -132,10 +133,16 @@ try {
var home; var home;
if (process.env['OS'] == 'Windows_NT') { if (isWindows) {
console.log('Preparing ssh-agent service on Windows'); console.log('Preparing ssh-agent service on Windows');
child_process.execSync('sc config ssh-agent start=demand', { stdio: 'inherit' }); child_process.execSync('sc config ssh-agent start=demand', { stdio: 'inherit' });
// Work around https://github.com/PowerShell/openssh-portable/pull/447 by creating a \dev\tty file
/*fs.mkdirSync('c:\\dev');
fs.closeSync(fs.openSync('c:\\dev\\tty', 'a'));
fs.mkdirSync('d:\\dev');
fs.closeSync(fs.openSync('d:\\dev\\tty', 'a'));*/
home = os.homedir(); home = os.homedir();
} else { } else {
// Use getent() system call, since this is what ssh does; makes a difference in Docker-based // Use getent() system call, since this is what ssh does; makes a difference in Docker-based
@ -168,41 +175,68 @@ try {
} }
} }
console.log("Adding private key to agent"); console.log("Adding private keys to agent");
var keyNumber = 0;
privateKey.split(/(?=-----BEGIN)/).forEach(function(key) { privateKey.split(/(?=-----BEGIN)/).forEach(function(key) {
child_process.execSync('ssh-add -', { input: key.trim() + "\n" }); ++keyNumber;
let keyFile = `${homeSsh}/key_${keyNumber}`;
// Write private key (unencrypted!) to file
console.log(`Write file ${keyFile}`);
fs.writeFileSync(keyFile, key.replace("\r\n", "\n").trim() + "\n", { mode: '600' });
// Set private key passphrase
let output = '';
try {
console.log(`Set passphrase on ${keyFile}`);
output = child_process.execFileSync('ssh-keygen', ['-p', '-f', keyFile, '-N', token]);
} catch (exception) {
fs.unlinkSync(keyFile);
throw exception;
}
// Load key into agent
if (isWindows) {
child_process.execFileSync('ssh-add', [keyFile], { env: { ...process.env, ...{ 'DISPLAY': 'fake', 'SSH_PASS': token, 'SSH_ASKPASS': 'D:\\a\\ssh-agent\\ssh-agent\\askpass.exe' } } });
} else {
child_process.execFileSync('ssh-add', [keyFile], { env: process.env, input: token });
}
output.toString().split(/\r?\n/).forEach(function(key) {
let parts = key.match(/^Key has comment '.*\bgithub\.com[:/]([_.a-z0-9-]+\/[_.a-z0-9-]+?)(?=\.git|\s|\')/);
if (parts == null) {
return;
}
let ownerAndRepo = parts[1];
child_process.execSync(`git config --global --replace-all url."git@key-${keyNumber}:${ownerAndRepo}".insteadOf "https://github.com/${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${keyNumber}:${ownerAndRepo}".insteadOf "git@github.com:${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${keyNumber}:${ownerAndRepo}".insteadOf "ssh://git@github.com/${ownerAndRepo}"`);
// On Linux and OS X, IdentitiesOnly=no will send all keys from agent before the explicit key, so use "yes".
// On Windows, IdentitiesOnly=yes will ignore keys from the agent, but send explicit keys first; so use "no" (https://github.com/PowerShell/Win32-OpenSSH/issues/1550)
//let identitiesOnly = isWindows ? 'no' : 'yes';
let sshConfig = `\nHost key-${keyNumber}\n`
+ ` HostName github.com\n`
+ ` User git\n`
+ ` IdentitiesOnly yes\n`
+ ` AddKeysToAgent yes\n`
+ ` IdentityFile ${keyFile}\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use key #${keyNumber} for GitHub repository ${ownerAndRepo}`);
});
}); });
console.log("Keys added:"); console.log("Keys added:");
child_process.execSync('ssh-add -l', { stdio: 'inherit' }); child_process.execSync('ssh-add -l', { stdio: 'inherit' });
child_process.execFileSync('ssh-add', ['-L']).toString().split(/\r?\n/).forEach(function(key) {
let parts = key.match(/\bgithub.com[:/](.*)(?:\.git)?\b/);
if (parts == null) {
return;
}
let ownerAndRepo = parts[1];
let sha256 = crypto.createHash('sha256').update(key).digest('hex');
fs.writeFileSync(`${homeSsh}/${sha256}`, key + "\n", { mode: '600' });
child_process.execSync(`git config --global --replace-all url."git@${sha256}:${ownerAndRepo}".insteadOf "https://github.com/${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@${sha256}:${ownerAndRepo}".insteadOf "git@github.com:${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@${sha256}:${ownerAndRepo}".insteadOf "ssh://git@github.com/${ownerAndRepo}"`);
let sshConfig = `\nHost ${sha256}\n`
+ ` HostName github.com\n`
+ ` User git\n`
+ ` IdentityFile ${homeSsh}/${sha256}\n`
+ ` IdentitiesOnly yes\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use key "${key}" for GitHub repository ${ownerAndRepo}`);
});
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }

View file

@ -2,7 +2,8 @@ const core = require('@actions/core');
const child_process = require('child_process'); const child_process = require('child_process');
const fs = require('fs'); const fs = require('fs');
const os = require('os'); const os = require('os');
const crypto = require('crypto'); const token = require('crypto').randomBytes(64).toString('hex');
const isWindows = (process.env['OS'] == 'Windows_NT');
try { try {
const privateKey = core.getInput('ssh-private-key'); const privateKey = core.getInput('ssh-private-key');
@ -15,10 +16,16 @@ try {
var home; var home;
if (process.env['OS'] == 'Windows_NT') { if (isWindows) {
console.log('Preparing ssh-agent service on Windows'); console.log('Preparing ssh-agent service on Windows');
child_process.execSync('sc config ssh-agent start=demand', { stdio: 'inherit' }); child_process.execSync('sc config ssh-agent start=demand', { stdio: 'inherit' });
// Work around https://github.com/PowerShell/openssh-portable/pull/447 by creating a \dev\tty file
/*fs.mkdirSync('c:\\dev');
fs.closeSync(fs.openSync('c:\\dev\\tty', 'a'));
fs.mkdirSync('d:\\dev');
fs.closeSync(fs.openSync('d:\\dev\\tty', 'a'));*/
home = os.homedir(); home = os.homedir();
} else { } else {
// Use getent() system call, since this is what ssh does; makes a difference in Docker-based // Use getent() system call, since this is what ssh does; makes a difference in Docker-based
@ -51,41 +58,68 @@ try {
} }
} }
console.log("Adding private key to agent"); console.log("Adding private keys to agent");
var keyNumber = 0;
privateKey.split(/(?=-----BEGIN)/).forEach(function(key) { privateKey.split(/(?=-----BEGIN)/).forEach(function(key) {
child_process.execSync('ssh-add -', { input: key.trim() + "\n" }); ++keyNumber;
let keyFile = `${homeSsh}/key_${keyNumber}`;
// Write private key (unencrypted!) to file
console.log(`Write file ${keyFile}`);
fs.writeFileSync(keyFile, key.replace("\r\n", "\n").trim() + "\n", { mode: '600' });
// Set private key passphrase
let output = '';
try {
console.log(`Set passphrase on ${keyFile}`);
output = child_process.execFileSync('ssh-keygen', ['-p', '-f', keyFile, '-N', token]);
} catch (exception) {
fs.unlinkSync(keyFile);
throw exception;
}
// Load key into agent
if (isWindows) {
child_process.execFileSync('ssh-add', [keyFile], { env: { ...process.env, ...{ 'DISPLAY': 'fake', 'SSH_PASS': token, 'SSH_ASKPASS': 'D:\\a\\ssh-agent\\ssh-agent\\askpass.exe' } } });
} else {
child_process.execFileSync('ssh-add', [keyFile], { env: process.env, input: token });
}
output.toString().split(/\r?\n/).forEach(function(key) {
let parts = key.match(/^Key has comment '.*\bgithub\.com[:/]([_.a-z0-9-]+\/[_.a-z0-9-]+?)(?=\.git|\s|\')/);
if (parts == null) {
return;
}
let ownerAndRepo = parts[1];
child_process.execSync(`git config --global --replace-all url."git@key-${keyNumber}:${ownerAndRepo}".insteadOf "https://github.com/${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${keyNumber}:${ownerAndRepo}".insteadOf "git@github.com:${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${keyNumber}:${ownerAndRepo}".insteadOf "ssh://git@github.com/${ownerAndRepo}"`);
// On Linux and OS X, IdentitiesOnly=no will send all keys from agent before the explicit key, so use "yes".
// On Windows, IdentitiesOnly=yes will ignore keys from the agent, but send explicit keys first; so use "no" (https://github.com/PowerShell/Win32-OpenSSH/issues/1550)
//let identitiesOnly = isWindows ? 'no' : 'yes';
let sshConfig = `\nHost key-${keyNumber}\n`
+ ` HostName github.com\n`
+ ` User git\n`
+ ` IdentitiesOnly yes\n`
+ ` AddKeysToAgent yes\n`
+ ` IdentityFile ${keyFile}\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use key #${keyNumber} for GitHub repository ${ownerAndRepo}`);
});
}); });
console.log("Keys added:"); console.log("Keys added:");
child_process.execSync('ssh-add -l', { stdio: 'inherit' }); child_process.execSync('ssh-add -l', { stdio: 'inherit' });
child_process.execFileSync('ssh-add', ['-L']).toString().split(/\r?\n/).forEach(function(key) {
let parts = key.match(/\bgithub.com[:/](.*)(?:\.git)?\b/);
if (parts == null) {
return;
}
let ownerAndRepo = parts[1];
let sha256 = crypto.createHash('sha256').update(key).digest('hex');
fs.writeFileSync(`${homeSsh}/${sha256}`, key + "\n", { mode: '600' });
child_process.execSync(`git config --global --replace-all url."git@${sha256}:${ownerAndRepo}".insteadOf "https://github.com/${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@${sha256}:${ownerAndRepo}".insteadOf "git@github.com:${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@${sha256}:${ownerAndRepo}".insteadOf "ssh://git@github.com/${ownerAndRepo}"`);
let sshConfig = `\nHost ${sha256}\n`
+ ` HostName github.com\n`
+ ` User git\n`
+ ` IdentityFile ${homeSsh}/${sha256}\n`
+ ` IdentitiesOnly yes\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use key "${key}" for GitHub repository ${ownerAndRepo}`);
});
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }