-
Notifications
You must be signed in to change notification settings - Fork 1k
Fixes #39657 - drop sshkey gem and replace with ssh-keygen cmd #11185
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
Changes from all commits
c661c17
e47cbac
c6cc943
57716eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: In config/initializers/inflections.rb is the following comment: Is that still relevant, or can we remove it?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
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 | ||
| 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 | ||
|
lzap marked this conversation as resolved.
|
||
| 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 |
| 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 |
| 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 |
| 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----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAr7vpNeZNpJmTeqNAcvyzsn02ZazZLY23Iqni413GBnVfEVo0DXxoyU0fOXJJ2cr/+0CC985lJJMm6GfeeZrko= foreman@example.com |
| 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----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBGOd0PSn18egNV/XfFXKLIDYcXjKAPLOTqCVuDOxypDfqlVSYr/EtfzN84F1yanQUCAm+A6gLfA43EmfHA8cZC4hW8T1mbHF9srt1EBckdw/9gRNk4kXBvugSINQldoXgw== foreman@example.com |
| 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----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAC6lkGQ38HcNIK1UwwSB2Yr4VLwKW2f75RJ0ZElc3ArCaiF62eIpVA+52mryN6sVaRqaoXZC62SiYZxozTmh5o6VwFsIRC2PAU//5XKAR78jA4ZFDBnulvPHBcm1QqpOKAWa+VsSYz3YUmwyBYXmDkbnPRlcjuZAqjrSPzWxapxCjGaDA== foreman@example.com |
| 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----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAN66m3Mz63QcXg5SDwXbmqYe7yAh5x46twjg1IVisP foreman@example.com |
| 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----- |
| 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 |
There was a problem hiding this comment.
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
sshkeygem dependency, should we also remove the obsoleterubygem-sshkey?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
theforeman/foreman-packaging#14089