Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dingpf/sshproxy #2

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,26 @@ end
This is how you would repeatedly poll the SFAPI to check if the command is done
running. `SFAPI.Executable.result` does repeatedly check the status, and fetches
the result when done (continuously refreshing the API token). So progress is
made even when not checking `istaskdone`.
made even when not checking `istaskdone`.

### Obtaining a sshproxy key/certificate

You can create a script like the following to use on the command line.

```bash
#!/usr/bin/env julia
include("<path-to-Superfacility.jl>/Superfacility")
push!(LOAD_PATH, "<path-to-Superfacility.jl>/Superfacility/Superfacility")
using Superfacility: SshProxy
SshProxy.sshproxy()
```

```
$ ./sshproxy_jl -h
usage: sshproxy_jl [--username USERNAME] [--collab COLLAB] [-h]

optional arguments:
--username USERNAME
--collab COLLAB
-h, --help show this help message and exit
```
7 changes: 5 additions & 2 deletions Superfacility/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Superfacility"
uuid = "f7a38f07-e5d6-4eec-ba19-7d8f01225f45"
authors = ["Johannes Blaschke <[email protected]>"]
version = "0.1.0"
version = "0.2.0"

[deps]
Chain = "8be319e6-bccf-4806-a6f7-6fae938471bc"
Expand All @@ -12,6 +12,9 @@ JSONWebTokens = "9b8beb19-0777-58c6-920b-28f749fee4d3"
ResultTypes = "08a2b407-ddc3-586a-afd6-c784ad1fffe2"
TimeZones = "f269a46b-ccf7-5d73-abea-4c690281aa53"
URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"


[compat]
julia = "1.6"
Expand All @@ -21,4 +24,4 @@ JSON = "0.21"
JSONWebTokens = "1"
ResultTypes = "3"
TimeZones = "1"
URIs = "1"
URIs = "1"
4 changes: 4 additions & 0 deletions Superfacility/src/Superfacility.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ include("status.jl")
using .Status

end # module SFAPI

include("sshproxy.jl")
using .SshProxy

end
88 changes: 88 additions & 0 deletions Superfacility/src/sshproxy.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
module SshProxy

using HTTP
using JSON
using Base64
using ArgParse

const KEY_PAIR_URL = "https://sshproxy.nersc.gov/create_pair/default/"
const COLLAB_URL = "https://sshproxy.nersc.gov/create_pair/collab/"

function get_key(username::Union{Nothing, String}, collab::Union{Nothing, String})
url, data, key_name = if isnothing(collab)
(KEY_PAIR_URL, Dict(), "nersc")
else
(COLLAB_URL, Dict("target_user" => collab), collab)
end

username = username === nothing ? ENV["USER"] : username

passwd = Base.getpass("Password+OTP")
user_pw = read(passwd, String)

keypath = joinpath(ENV["HOME"], ".ssh")
private = joinpath(keypath, key_name)
public = joinpath(keypath, "$key_name.pub")
pub_cert = joinpath(keypath, "$key_name-cert.pub")

isfile(private) && rm(private)
isfile(public) && rm(public)

res = HTTP.post(url, body=JSON.json(data),
headers=Dict("Content-Type" => "Application/json", "Authorization" => "Basic $(Base64.base64encode("$username:$user_pw"))"))
Base.shred!(passwd)

if res.status != 200
throw(ErrorException("Failed to get key: $(res.status)"))
end

out = String(res.body)
pub_index = findfirst("ssh-rsa-cert-v01", out)

if pub_index === nothing
throw(ErrorException("Invalid response from server"))
end

key_sep = "-----END RSA PRIVATE KEY-----\n"
private_key, pub_key = split(out, key_sep)
private_key = string(private_key, key_sep)

# Write the files
open(pub_cert, "w") do f
write(f, pub_key)
end
open(private, "w") do f
write(f, private_key)
end
chmod(private, 0o600)

public_pem = read(`ssh-keygen -y -f $private`, String)
open(public, "w") do f
write(f, public_pem)
end

end

function sshproxy()
s = ArgParseSettings()
@add_arg_table s begin
"--username"
"--collab"
end

parsed_args = parse_args(s)
username = get(parsed_args, "username", nothing)
collab = get(parsed_args, "collab", nothing)

try
get_key(username, collab)
catch e
rethrow(e)
exit(1)
end
exit(0)
end

export sshproxy

end