Class: Nonnative::SshToken

Inherits:
Object
  • Object
show all
Defined in:
lib/nonnative/ssh_token.rb

Overview

Generates go-service style SSH tokens for authenticating against services under test.

Despite the name this is not an SSH protocol signature: the key is loaded from an OpenSSH-format Ed25519 private key and used as a raw Ed25519 key, matching go-service's SSH token scheme. The token is <base64(claims)>.<base64(signature)>, where the signature is a raw Ed25519 signature over the claims JSON. Claims are ver/kid/sub/aud/iat/exp, with sub == kid == key and iat/exp in Unix nanoseconds. issuer and sub are accepted for a uniform interface with the other kinds but unused: SSH tokens have no issuer, and the subject is always the key id.

Examples:

ssh = Nonnative::SshToken.new(key: 'key-1', private_key: 'config/id_ed25519', expiration: 3600)
ssh.generate(aud: 'GET /v1/things', sub: 'user-1')

See Also:

Constant Summary collapse

TOKEN_VERSION =

The go-service SSH token format version.

'v1'

Instance Method Summary collapse

Constructor Details

#initialize(key:, private_key:, expiration:) ⇒ SshToken

Returns a new instance of SshToken.

Parameters:

  • key (String)

    the key id; also used as the subject

  • private_key (String)

    path to an OpenSSH-format Ed25519 private key file

  • expiration (Integer)

    token lifetime in seconds (drives exp)



25
26
27
28
29
# File 'lib/nonnative/ssh_token.rb', line 25

def initialize(key:, private_key:, expiration:, **)
  @key = key
  @private_key = private_key
  @expiration = expiration
end

Instance Method Details

#generate(aud:) ⇒ String

Generates a signed SSH token.

Parameters:

  • aud (String)

    the aud claim (for example "GET /v1/things" or a gRPC full method)

Returns:

  • (String)

    the token, "<base64(claims)>.<base64(signature)>"



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/nonnative/ssh_token.rb', line 35

def generate(aud:, **)
  now = Time.now
  issued_at = (now.to_i * 1_000_000_000) + now.nsec
  claims = {
    ver: TOKEN_VERSION,
    kid: @key,
    sub: @key,
    aud: aud,
    iat: issued_at,
    exp: issued_at + (@expiration * 1_000_000_000)
  }.to_json

  signature = Ed25519::SigningKey.new(seed).sign(claims)

  "#{Base64.strict_encode64(claims)}.#{Base64.strict_encode64(signature)}"
end