Skip to content

Commit

Permalink
Merge pull request #153 from dscho/limit-access-to-actor-auto
Browse files Browse the repository at this point in the history
Default to using public key authentication (if any public SSH key is registered)
  • Loading branch information
dscho authored May 17, 2023
2 parents 1005f9c + 4d571a0 commit 73f5c99
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ jobs:

## Use registered public SSH key(s)

By default anybody can connect to the tmate session. You can opt-in to install the public SSH keys [that you have registered with your GitHub profile](https://docs.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account).
If [you have registered one or more public SSH keys with your GitHub profile](https://docs.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account), tmate will be started such that only those keys are authorized to connect, otherwise anybody can connect to the tmate session. If you want to require a public SSH key to be installed with the tmate session, no matter whether the user who started the workflow has registered any in their GitHub profile, you will need to configure the setting `limit-access-to-actor` to `true`, like so:

```yaml
name: CI
Expand Down
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ inputs:
required: false
default: 'true'
limit-access-to-actor:
description: 'If only the public SSH keys of the user triggering the workflow should be authorized'
description: 'Whether to authorize only the public SSH keys of the user triggering the workflow (defaults to true if the GitHub profile of the user has a public SSH key)'
required: false
default: 'false'
default: 'auto'
tmate-server-host:
description: 'The hostname for your tmate server (e.g. ssh.example.org)'
required: false
Expand Down
26 changes: 19 additions & 7 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12630,7 +12630,10 @@ async function run() {
}

let newSessionExtra = ""
if (core.getInput("limit-access-to-actor") === "true") {
let tmateSSHDashI = ""
let publicSSHKeysWarning = ""
const limitAccessToActor = core.getInput("limit-access-to-actor")
if (limitAccessToActor === "true" || limitAccessToActor === "auto") {
const { actor, apiUrl } = github.context
const auth = core.getInput('github-token')
const octokit = new dist_node/* Octokit */.v({ auth, baseUrl: apiUrl })
Expand All @@ -12639,13 +12642,16 @@ async function run() {
username: actor
})
if (keys.data.length === 0) {
throw new Error(`No public SSH keys registered with ${actor}'s GitHub profile`)
if (limitAccessToActor === "auto") publicSSHKeysWarning = `No public SSH keys found for ${actor}; continuing without them even if it is less secure (please consider adding an SSH key, see https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account)`
else throw new Error(`No public SSH keys registered with ${actor}'s GitHub profile`)
} else {
const sshPath = external_path_default().join(external_os_default().homedir(), ".ssh")
await external_fs_default().promises.mkdir(sshPath, { recursive: true })
const authorizedKeysPath = external_path_default().join(sshPath, "authorized_keys")
await external_fs_default().promises.writeFile(authorizedKeysPath, keys.data.map(e => e.key).join('\n'))
newSessionExtra = `-a "${authorizedKeysPath}"`
tmateSSHDashI = "ssh -i <path-to-private-SSH-key>"
}
const sshPath = external_path_default().join(external_os_default().homedir(), ".ssh")
await external_fs_default().promises.mkdir(sshPath, { recursive: true })
const authorizedKeysPath = external_path_default().join(sshPath, "authorized_keys")
await external_fs_default().promises.writeFile(authorizedKeysPath, keys.data.map(e => e.key).join('\n'))
newSessionExtra = `-a "${authorizedKeysPath}"`
}

const tmate = `${tmateExecutable} -S /tmp/tmate.sock`;
Expand Down Expand Up @@ -12684,10 +12690,16 @@ async function run() {

core.debug("Entering main loop")
while (true) {
if (publicSSHKeysWarning) {
core.warning(publicSSHKeysWarning)
}
if (tmateWeb) {
core.info(`Web shell: ${tmateWeb}`);
}
core.info(`SSH: ${tmateSSH}`);
if (tmateSSHDashI) {
core.info(`or: ${tmateSSH.replace(/^ssh/, tmateSSHDashI)}`)
}

if (continueFileExists()) {
core.info("Exiting debugging session because the continue file was created")
Expand Down
26 changes: 19 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ export async function run() {
}

let newSessionExtra = ""
if (core.getInput("limit-access-to-actor") === "true") {
let tmateSSHDashI = ""
let publicSSHKeysWarning = ""
const limitAccessToActor = core.getInput("limit-access-to-actor")
if (limitAccessToActor === "true" || limitAccessToActor === "auto") {
const { actor, apiUrl } = github.context
const auth = core.getInput('github-token')
const octokit = new Octokit({ auth, baseUrl: apiUrl })
Expand All @@ -88,13 +91,16 @@ export async function run() {
username: actor
})
if (keys.data.length === 0) {
throw new Error(`No public SSH keys registered with ${actor}'s GitHub profile`)
if (limitAccessToActor === "auto") publicSSHKeysWarning = `No public SSH keys found for ${actor}; continuing without them even if it is less secure (please consider adding an SSH key, see https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account)`
else throw new Error(`No public SSH keys registered with ${actor}'s GitHub profile`)
} else {
const sshPath = path.join(os.homedir(), ".ssh")
await fs.promises.mkdir(sshPath, { recursive: true })
const authorizedKeysPath = path.join(sshPath, "authorized_keys")
await fs.promises.writeFile(authorizedKeysPath, keys.data.map(e => e.key).join('\n'))
newSessionExtra = `-a "${authorizedKeysPath}"`
tmateSSHDashI = "ssh -i <path-to-private-SSH-key>"
}
const sshPath = path.join(os.homedir(), ".ssh")
await fs.promises.mkdir(sshPath, { recursive: true })
const authorizedKeysPath = path.join(sshPath, "authorized_keys")
await fs.promises.writeFile(authorizedKeysPath, keys.data.map(e => e.key).join('\n'))
newSessionExtra = `-a "${authorizedKeysPath}"`
}

const tmate = `${tmateExecutable} -S /tmp/tmate.sock`;
Expand Down Expand Up @@ -133,10 +139,16 @@ export async function run() {

core.debug("Entering main loop")
while (true) {
if (publicSSHKeysWarning) {
core.warning(publicSSHKeysWarning)
}
if (tmateWeb) {
core.info(`Web shell: ${tmateWeb}`);
}
core.info(`SSH: ${tmateSSH}`);
if (tmateSSHDashI) {
core.info(`or: ${tmateSSH.replace(/^ssh/, tmateSSHDashI)}`)
}

if (continueFileExists()) {
core.info("Exiting debugging session because the continue file was created")
Expand Down

0 comments on commit 73f5c99

Please sign in to comment.