Skip to content
Merged
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
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ gem 'responders', '~> 3.0'
gem 'roadie-rails', '~> 3.0'
gem 'deacon', '~> 1.0'
gem 'mail', '~> 2.7'
gem 'sshkey', '~> 2.0'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this PR removes the sshkey gem dependency, should we also remove the obsolete rubygem-sshkey?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gem 'dynflow', '>= 1.6.5', '< 3.0.0'
gem 'daemons'
gem 'bcrypt', '~> 3.1'
Expand Down
8 changes: 4 additions & 4 deletions app/models/ssh_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,19 @@ def self.title_name
def generate_fingerprint
self.fingerprint = nil
return unless key.present?
self.fingerprint = SSHKey.sha256_fingerprint(key)
self.fingerprint = Foreman::Provision::SshKey.new(key).fingerprint
true
rescue SSHKey::PublicKeyError => exception
rescue Foreman::Provision::SshKey::Error => exception
Foreman::Logging.exception("Could not calculate SSH key fingerprint", exception)
nil
end

def calculate_length
self.length = nil
return unless key.present?
self.length = SSHKey.ssh_public_key_bits(key)
self.length = Foreman::Provision::SshKey.new(key).length
true
rescue SSHKey::PublicKeyError => exception
rescue Foreman::Provision::SshKey::Error => exception
Foreman::Logging.exception("Could not calculate SSH key length", exception)
nil
end
Expand Down
99 changes: 99 additions & 0 deletions app/services/foreman/provision/ssh_key.rb

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

In config/initializers/inflections.rb is the following comment:

  # Causes an overlap between ::SSHKey and the SshKey model
  # inflect.acronym 'SSH' # Secure SHell

Is that still relevant, or can we remove it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is still relevant, I thought about either renaming the package/namespace or leaving the inflection as-is.

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
require 'open3'
require 'tmpdir'

# Wraps the SSH public key operations (fingerprinting, key length and
# validation) behind a single interface. The work is delegated to the OpenSSH
# ssh-keygen command line tool so no third party gem (and its own crypto
# implementation) is needed, which keeps the behaviour aligned with OpenSSH and
# friendly to FIPS/PQC requirements.
class Foreman::Provision::SshKey
Comment thread
lzap marked this conversation as resolved.
# Raised when the key cannot be processed (e.g. malformed public key).
class Error < StandardError; end

# Generates a brand new SSH key pair with ssh-keygen and returns its public
# key as an OpenSSH format string, i.e. the value that would be stored on an
# SshKey record. The key pair is created in a temporary directory and the
# private key is discarded; only the public key is returned.
#
# This is meant to be used by tests and plugins that need a valid, unique
# public key without shipping a static fixture.
#
# Parameters:
# type: optional key type passed to `ssh-keygen -t` (e.g. rsa, ecdsa,
# ed25519). When omitted, ssh-keygen picks its own default type.
# comment: comment appended to the public key via `ssh-keygen -C`.
# bits: optional key size passed to `ssh-keygen -b`. Ignored by key
# types with a fixed size such as ed25519.
#
# Returns the public key String. Raises Error when ssh-keygen fails.
def self.generate(type: nil, comment: '', bits: nil)
Dir.mktmpdir('foreman-ssh-key') do |dir|
path = File.join(dir, 'key')
args = ['ssh-keygen', '-N', '', '-C', comment.to_s, '-f', path] + ssh_keygen_verbosity_args(:quiet => true)
args += ['-t', type.to_s] if type
args += ['-b', bits.to_s] if bits
_stdout, stderr, status = Open3.capture3(*args)
raise Error, "unable to generate SSH key: #{stderr}" unless status.success?

File.read("#{path}.pub").strip
end
end

attr_reader :key

def initialize(key)
@key = key
end

# Returns the SHA256 fingerprint of the public key, base64 encoded (without
# the "SHA256:" prefix ssh-keygen would print).
def fingerprint
info.fetch(:fingerprint)
end

# Returns the length of the public key in bits.
def length
info.fetch(:length)
end

# Returns true when the given public key is valid.
def valid?
parse
true
rescue Error
false
end

def self.ssh_keygen_verbosity_args(quiet: false)
if Rails.env.development?
['-v']
elsif quiet
['-q']
else
[]
end
end

private

def info
@info ||= parse
end

# Runs `ssh-keygen -l` against the key (fed via stdin) and parses its output,
# which looks like: "256 SHA256:<base64> comment (ED25519)".
def parse
stdout, _stderr, status = Open3.capture3(*(['ssh-keygen', '-l', '-f', '-'] + self.class.ssh_keygen_verbosity_args), :stdin_data => key.to_s)
raise Error, 'not a valid public ssh key' unless status.success?

bits, fingerprint, = stdout.split(' ', 3)
{ :length => bits.to_i, :fingerprint => format_fingerprint(fingerprint) }
end

# ssh-keygen prints the fingerprint prefixed with "SHA256:" and strips the
# base64 padding. Restore the padding so the value stays stable across tools.
def format_fingerprint(raw)
encoded = raw.to_s.delete_prefix('SHA256:')
encoded + ('=' * ((4 - (encoded.length % 4)) % 4))
end
end
4 changes: 2 additions & 2 deletions app/validators/ssh_key_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ def validate_each(record, attribute, value)
private

def valid_ssh_public_key?(key)
SSHKey.valid_ssh_public_key?(key)
rescue SSHKey::PublicKeyError => exception
Foreman::Provision::SshKey.new(key).valid?
rescue Foreman::Provision::SshKey::Error => exception
Foreman::Logging.exception("Invalid SSH public key", exception)
false
end
Expand Down
18 changes: 16 additions & 2 deletions db/migrate/20200127103144_ssh_keys_fingerprints_sha1.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
require 'digest/sha2'
require 'digest/md5'
require 'base64'

class SshKeysFingerprintsSha1 < ActiveRecord::Migration[5.2]
def up
SshKey.all.each { |ssh_key| ssh_key.update_column('fingerprint', SSHKey.sha256_fingerprint(ssh_key.key)) }
update_fingerprints { |blob| Base64.strict_encode64(Digest::SHA256.digest(blob)) }
end

def down
SshKey.all.each { |ssh_key| ssh_key.update_column('fingerprint', SSHKey.fingerprint(ssh_key.key)) }
update_fingerprints { |blob| Digest::MD5.hexdigest(blob).scan(/../).join(':') }
end

private

def update_fingerprints
SshKey.reset_column_information
SshKey.all.each do |ssh_key|
blob = Base64.decode64(ssh_key.key.to_s.split(' ')[1].to_s)
ssh_key.update_column('fingerprint', yield(blob))
end
end
end
Comment thread
lzap marked this conversation as resolved.
8 changes: 5 additions & 3 deletions test/factories/ssh_key.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
FactoryBot.define do
factory :ssh_key do
sequence(:name) { |n| "user#{n}@example.com" }
sequence(:key) do |n|
[SSHKey.generate.ssh_public_key, "foreman#{n}@example.com"].join(' ')
end
# Each build shells out to ssh-keygen to create a fresh, unique key pair.
# This is safe to do for as many keys as the tests need: on modern kernels
# (Linux >= 5.6) /dev/random no longer blocks once the CRNG has been seeded
# early at boot, so key generation never stalls waiting for entropy.
sequence(:key) { |n| Foreman::Provision::SshKey.generate(comment: "foreman#{n}@example.com") }
association :user, :factory => :user
end
end
28 changes: 28 additions & 0 deletions test/migrate/ssh_keys_fingerprints_sha1_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'test_helper'
require Rails.root.join('db/migrate/20200127103144_ssh_keys_fingerprints_sha1.rb')

class SshKeysFingerprintsSha1Test < ActiveSupport::TestCase
let(:migration) { SshKeysFingerprintsSha1.new }

# A key fixture with pre-computed fingerprints in both formats.
let(:key) { File.read(Rails.root.join('test/static_fixtures/ssh_keys/ed25519.pub')).strip }
let(:sha256_fingerprint) { 'dkKrxf6K2+QZlM3c0JMc7pGvr33OkamPFAG+6n93v5k=' }
let(:md5_fingerprint) { '2f:96:e2:14:3e:ae:b4:78:b8:fa:1e:85:da:14:f9:69' }
let(:ssh_key) { FactoryBot.create(:ssh_key, :key => key) }

test 'up rewrites the fingerprint into the sha256 format' do
ssh_key.update_column('fingerprint', 'stale-fingerprint')

migration.up

assert_equal sha256_fingerprint, ssh_key.reload.fingerprint
end

test 'down rewrites the fingerprint into the legacy md5 format' do
assert_equal sha256_fingerprint, ssh_key.reload.fingerprint

migration.down

assert_equal md5_fingerprint, ssh_key.reload.fingerprint
end
end
101 changes: 101 additions & 0 deletions test/services/foreman/provision/ssh_key_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
require 'test_helper'

class Foreman::Provision::SshKeyTest < ActiveSupport::TestCase
KEYS = {
'rsa2048' => { fingerprint: 'YM91jAmHbxhgh/d1NtHzBtGqqR1ARwVb0KDF0pGZAVc=', length: 2048 },
'rsa4096' => { fingerprint: '8rD/tQMje6HUk1dZELelNM5SMpiGO+1BrEgrfSZdvg0=', length: 4096 },
'ecdsa256' => { fingerprint: '4dEJKo6jNj7vVT6Y90D5UQf6QIJ6/U65GAlP+C86zhw=', length: 256 },
'ecdsa384' => { fingerprint: 'wFWPwwLl/pMIsCcJATtzNuly0V4rIQcyS6Bp8Icrb5Y=', length: 384 },
'ecdsa521' => { fingerprint: '3x7Jb/6rsjGjALMvKGznxc9cw+63YCHhXeOnJ9qs7DM=', length: 521 },
'ed25519' => { fingerprint: 'dkKrxf6K2+QZlM3c0JMc7pGvr33OkamPFAG+6n93v5k=', length: 256 },
}.freeze

def public_key(name)
File.read(Rails.root.join("test/static_fixtures/ssh_keys/#{name}.pub")).strip
end

KEYS.each do |name, expected|
context "with a #{name} public key" do
let(:key) { public_key(name) }
let(:service) { Foreman::Provision::SshKey.new(key) }

test 'is valid' do
assert service.valid?
end

test 'calculates the fingerprint' do
assert_equal expected[:fingerprint], service.fingerprint
end

test 'calculates the length' do
assert_equal expected[:length], service.length
end
end
end

context 'with an unparseable key' do
let(:service) { Foreman::Provision::SshKey.new('this-is-not-a-key') }

test 'is not valid' do
refute service.valid?
end

test 'raises Error when calculating the fingerprint' do
assert_raises(Foreman::Provision::SshKey::Error) { service.fingerprint }
end

test 'raises Error when calculating the length' do
assert_raises(Foreman::Provision::SshKey::Error) { service.length }
end
end

context 'when the underlying implementation raises' do
let(:key) { public_key('rsa2048') }
let(:service) { Foreman::Provision::SshKey.new(key) }

setup do
Open3.stubs(:capture3).returns(['', 'ssh-keygen boom', stub(:success? => false)])
end

test 'raises Error when calculating the fingerprint' do
assert_raises(Foreman::Provision::SshKey::Error) { service.fingerprint }
end

test 'raises Error when calculating the length' do
assert_raises(Foreman::Provision::SshKey::Error) { service.length }
end

test 'reports the key as invalid' do
refute service.valid?
end
end

context '.generate' do
test 'generates a valid public key' do
key = Foreman::Provision::SshKey.generate
assert Foreman::Provision::SshKey.new(key).valid?
end

%w[rsa ecdsa ed25519].each do |type|
test "generates a valid #{type} key" do
key = Foreman::Provision::SshKey.generate(:type => type)
assert Foreman::Provision::SshKey.new(key).valid?
end
end

test 'generates a unique key on every call' do
refute_equal Foreman::Provision::SshKey.generate, Foreman::Provision::SshKey.generate
end

test 'appends the given comment' do
key = Foreman::Provision::SshKey.generate(:comment => 'foreman@example.com')
assert_equal 'foreman@example.com', key.split(' ').last
end

test 'raises Error on an unknown key type' do
assert_raises(Foreman::Provision::SshKey::Error) do
Foreman::Provision::SshKey.generate(:type => 'nonsense')
end
end
end
end
9 changes: 9 additions & 0 deletions test/static_fixtures/ssh_keys/ecdsa256
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQK+76TXmTaSZk3qjQHL8s7J9NmWs2S
2NtyKp4uNdxgZ1XxFaNA18aMlNHzlySdnK//tAgvfOZSSTJuhn3nma5KAAAAsOkACiPpAA
ojAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAr7vpNeZNpJmTeq
NAcvyzsn02ZazZLY23Iqni413GBnVfEVo0DXxoyU0fOXJJ2cr/+0CC985lJJMm6GfeeZrk
oAAAAgH3unt7i/f4sNdh78zR/h+WICvBTX+CbYG5tRL6N0JkgAAAATZm9yZW1hbkBleGFt
cGxlLmNvbQECAwQF
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions test/static_fixtures/ssh_keys/ecdsa256.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAr7vpNeZNpJmTeqNAcvyzsn02ZazZLY23Iqni413GBnVfEVo0DXxoyU0fOXJJ2cr/+0CC985lJJMm6GfeeZrko= foreman@example.com
10 changes: 10 additions & 0 deletions test/static_fixtures/ssh_keys/ecdsa384
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRjndD0p9fHoDVf13xVyiyA2HF4ygDy
zk6glbgzscqQ36pVUmK/xLX8zfOBdcmp0FAgJvgOoC3wONxJnxwPHGQuIVvE9ZmxxfbK7d
RAXJHcP/YETZOJFwb7oEiDUJXaF4MAAADg8XZN4PF2TeAAAAATZWNkc2Etc2hhMi1uaXN0
cDM4NAAAAAhuaXN0cDM4NAAAAGEEY53Q9KfXx6A1X9d8VcosgNhxeMoA8s5OoJW4M7HKkN
+qVVJiv8S1/M3zgXXJqdBQICb4DqAt8DjcSZ8cDxxkLiFbxPWZscX2yu3UQFyR3D/2BE2T
iRcG+6BIg1CV2heDAAAAMBzbRcp3m1mAjMjiqb0oCf+Bkme3kmPCro3f4sj+CURvxL/ltC
oeJzfsmYFus6WREgAAABNmb3JlbWFuQGV4YW1wbGUuY29tAQIDBAU=
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions test/static_fixtures/ssh_keys/ecdsa384.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBGOd0PSn18egNV/XfFXKLIDYcXjKAPLOTqCVuDOxypDfqlVSYr/EtfzN84F1yanQUCAm+A6gLfA43EmfHA8cZC4hW8T1mbHF9srt1EBckdw/9gRNk4kXBvugSINQldoXgw== foreman@example.com
12 changes: 12 additions & 0 deletions test/static_fixtures/ssh_keys/ecdsa521
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS
1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAupZBkN/B3DSCtVMMEgdmK+FS8Clt
n++USdGRJXNwKwmohetniKVQPudpq8jerFWkamqF2QutkomGcaM05oeaOlcBbCEQtjwFP/
+VygEe/IwOGRQwZ7pbzxwXJtUKqTigFmvlbEmM92FJsMgWF5g5G5z0ZXI7mQKo60j81sWq
cQoxmgwAAAEYxcPVMcXD1TEAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ
AAAIUEALqWQZDfwdw0grVTDBIHZivhUvApbZ/vlEnRkSVzcCsJqIXrZ4ilUD7naavI3qxV
pGpqhdkLrZKJhnGjNOaHmjpXAWwhELY8BT//lcoBHvyMDhkUMGe6W88cFybVCqk4oBZr5W
xJjPdhSbDIFheYORuc9GVyO5kCqOtI/NbFqnEKMZoMAAAAQgDtVc63FMbeUN8XVKbSVFKy
rn8rXfo7m2aOEOzQ7MzpJUwfbeEg3Vnl9fd1Fe4kwtZpHBusd+O6n8STt03Drn1xtgAAAB
Nmb3JlbWFuQGV4YW1wbGUuY29tAQIDBAUGBw==
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions test/static_fixtures/ssh_keys/ecdsa521.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAC6lkGQ38HcNIK1UwwSB2Yr4VLwKW2f75RJ0ZElc3ArCaiF62eIpVA+52mryN6sVaRqaoXZC62SiYZxozTmh5o6VwFsIRC2PAU//5XKAR78jA4ZFDBnulvPHBcm1QqpOKAWa+VsSYz3YUmwyBYXmDkbnPRlcjuZAqjrSPzWxapxCjGaDA== foreman@example.com
7 changes: 7 additions & 0 deletions test/static_fixtures/ssh_keys/ed25519
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAgDeuptzM+t0HF4OUg8F25qmHu8gIeceOrcI4NSFYrDwAAAJi4tVTAuLVU
wAAAAAtzc2gtZWQyNTUxOQAAACAgDeuptzM+t0HF4OUg8F25qmHu8gIeceOrcI4NSFYrDw
AAAEA1ZMoryQ4tSS/uY5zX8HFWGWXQMLjvRM6Ix7rpCjMUjSAN66m3Mz63QcXg5SDwXbmq
Ye7yAh5x46twjg1IVisPAAAAE2ZvcmVtYW5AZXhhbXBsZS5jb20BAg==
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions test/static_fixtures/ssh_keys/ed25519.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAN66m3Mz63QcXg5SDwXbmqYe7yAh5x46twjg1IVisP foreman@example.com
27 changes: 27 additions & 0 deletions test/static_fixtures/ssh_keys/rsa2048
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAtJ6VaPKlwaPsJYRpk1fwsxsi/9tZaqubNZL46HryURZH+65wwc/r
P/e3MRvUipha5Zq6hjcz2/BiOgrxiih7saUGdTDZBQe9tWqu1VpdNe1YNnFHUGwzMjMVY0
PfXXrsutz+HeMWgsJdfl27DwFf5yPPR5KyxJs1hxoXSNH7DZnXz2kn8ZWApZPA1RzaTpNW
1TpMLPXDPHmd7y6kUOREBPvXxDItNIhGcEsCFtRVfcO39lV0/dkkaPIOah9rnkYUfwMmHt
4aeoAOMTpY993K9vY1p4tFOynKuYBbtQmll1FpZ19jNEq+bjmr2H22zcSu7Ru9nvYLMuVk
4Dc2IpgxXQAAA9DIgUcuyIFHLgAAAAdzc2gtcnNhAAABAQC0npVo8qXBo+wlhGmTV/CzGy
L/21lqq5s1kvjoevJRFkf7rnDBz+s/97cxG9SKmFrlmrqGNzPb8GI6CvGKKHuxpQZ1MNkF
B721aq7VWl017Vg2cUdQbDMyMxVjQ99deuy63P4d4xaCwl1+XbsPAV/nI89HkrLEmzWHGh
dI0fsNmdfPaSfxlYClk8DVHNpOk1bVOkws9cM8eZ3vLqRQ5EQE+9fEMi00iEZwSwIW1FV9
w7f2VXT92SRo8g5qH2ueRhR/AyYe3hp6gA4xOlj33cr29jWni0U7Kcq5gFu1CaWXUWlnX2
M0Sr5uOavYfbbNxK7tG72e9gsy5WTgNzYimDFdAAAAAwEAAQAAAQACtj7YDIygk62AArTz
GWbryYSFAu4cw+bYrxQ9qVrqDMOX686VmmGV3EpL2ncefZsfx2r1iO6mZr2S0Yc+48y3ph
qqt8kKYkte5fMqEOlFXgLtDlZbxsQeBNZVXzeDV80mIRtPp5E29WQh+ZZNa1/dQJRkJre4
a/wpwyKGXWC/m4E+N0YAOIYB+FGTb+Snf7CxreQaNyDhnBgMUvaPrR94oWYMbnQu+s3iqt
RGxNytImXwbr74wBP6o9cGAEgbqFktoauNCUHjgdGaLYc2GZYCntBY1HfnbB4fSLIKzfZi
GeUFzKv5cSRyc/uK/8/F112iI1kXp8KQ6Xrg4lGbwjIBAAAAgQCevSUPlBZHvmG/P177kO
wPaKv0JwYrUaMTLPJzhrFHoJmr58Pzdzc451Xd8ysquV28fQP65YYF/lvp19f8PfgOCnn+
r9yGV9axGsRDCwicyqsKwk8vqIUTwb33yj886eye9z9bpHWIBTkKXuAAvDaF0RBZ4cSLmb
SCRo0+87SWrAAAAIEA61pZmxRMeppIJKYol+tQHa1gS23YwyN7oQgCXo83mLJd8V+OU98g
V8DGy9XtKp7Rc/O4PI5ogynoeuceenCbyMnA29Hqy4GTqGMP4B1IBfbfCzDQh9K2/K7nGs
PFRuIh0g3UC1DfNXyNt6JvK5Ekotd6PjUKvhL+S9utXpW2KA0AAACBAMR3AfckbvKp6N3O
1QQbXjrhdJinYOCvofq2hQSMrvjqU1Ean4a/0NAfuITtWtLv1mi8tlnd/wJcOQNsSkeRcu
x+Z3Iuj6+N0ALxxjVO7jI3B9MkTlI/24I6xrKA4CiT0BROsm0xLaUll6mMmUUVTfj2J/Ea
m6JIeeJJ81cChwqRAAAAE2ZvcmVtYW5AZXhhbXBsZS5jb20BAgMEBQYH
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions test/static_fixtures/ssh_keys/rsa2048.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0npVo8qXBo+wlhGmTV/CzGyL/21lqq5s1kvjoevJRFkf7rnDBz+s/97cxG9SKmFrlmrqGNzPb8GI6CvGKKHuxpQZ1MNkFB721aq7VWl017Vg2cUdQbDMyMxVjQ99deuy63P4d4xaCwl1+XbsPAV/nI89HkrLEmzWHGhdI0fsNmdfPaSfxlYClk8DVHNpOk1bVOkws9cM8eZ3vLqRQ5EQE+9fEMi00iEZwSwIW1FV9w7f2VXT92SRo8g5qH2ueRhR/AyYe3hp6gA4xOlj33cr29jWni0U7Kcq5gFu1CaWXUWlnX2M0Sr5uOavYfbbNxK7tG72e9gsy5WTgNzYimDFd foreman@example.com
Loading
Loading