Skip to content
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
33 changes: 30 additions & 3 deletions lib/puppet/provider/sshkey/parsed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,42 @@

record_line :parsed, fields: ['name', 'type', 'key'],
post_parse: proc { |hash|
names = hash[:name].split(',', -1)
hash[:name] = names.shift
hash[:host_aliases] = names
# Check if this is a cert-authority line by looking at the name field
if hash[:name] && hash[:name] == '@cert-authority'
# Re-parse the cert-authority format: @cert-authority hostname keytype key
# The original fields were: name='@cert-authority', type='hostname', key='keytype actualkey'
hostname = hash[:type]
keytype_and_key = hash[:key].split(/\s+/, 2)
if keytype_and_key.length >= 2
keytype = keytype_and_key[0]
actual_key = keytype_and_key[1]
hash[:name] = hostname
hash[:type] = "@cert-authority #{keytype}"
hash[:key] = actual_key
end
end

# Handle host aliases for all entries
if hash[:name]
names = hash[:name].split(',', -1)
hash[:name] = names.shift
hash[:host_aliases] = names
end
},
pre_gen: proc { |hash|
if hash[:host_aliases]
hash[:name] = [hash[:name], hash[:host_aliases]].flatten.join(',')
hash.delete(:host_aliases)
end
# Handle cert-authority format
if hash[:type] && hash[:type].to_s.start_with?('@cert-authority ')
# Extract the key type from '@cert-authority ssh-rsa' format
key_type = hash[:type].to_s.sub(/^@cert-authority /, '')
# Reorder fields for cert-authority format: @cert-authority name key_type key
# We need to restructure to have three fields: name="@cert-authority hostname", type="keytype", key=key
hash[:name] = "@cert-authority #{hash[:name]}"
hash[:type] = key_type
end
}

# Make sure to use mode 644 if ssh_known_hosts is newly created
Expand Down
16 changes: 14 additions & 2 deletions lib/puppet/type/sshkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,30 @@ def self.title_patterns
end

newparam(:type) do
desc 'The encryption type used. Probably ssh-dss or ssh-rsa.'
desc 'The encryption type used. Probably ssh-dss or ssh-rsa.
For certificate authorities, use @cert-authority followed by the key type,
e.g., @cert-authority ssh-rsa. This will create an entry in the known_hosts
file formatted as "@cert-authority hostname keytype key" which allows SSH
to validate host certificates signed by the specified certificate authority.'

isnamevar

newvalues :'ssh-dss', :'ssh-ed25519', :'ssh-rsa', :'ecdsa-sha2-nistp256', :'ecdsa-sha2-nistp384', :'ecdsa-sha2-nistp521',
:'[email protected]', :'[email protected]'
:'[email protected]', :'[email protected]',
:'@cert-authority ssh-dss', :'@cert-authority ssh-ed25519', :'@cert-authority ssh-rsa',
:'@cert-authority ecdsa-sha2-nistp256', :'@cert-authority ecdsa-sha2-nistp384', :'@cert-authority ecdsa-sha2-nistp521',
:'@cert-authority [email protected]', :'@cert-authority [email protected]'

aliasvalue(:dsa, :'ssh-dss')
aliasvalue(:ed25519, :'ssh-ed25519')
aliasvalue(:rsa, :'ssh-rsa')
aliasvalue(:'ecdsa-sk', :'[email protected]')
aliasvalue(:'ed25519-sk', :'[email protected]')
aliasvalue(:'@cert-authority dsa', :'@cert-authority ssh-dss')
aliasvalue(:'@cert-authority ed25519', :'@cert-authority ssh-ed25519')
aliasvalue(:'@cert-authority rsa', :'@cert-authority ssh-rsa')
aliasvalue(:'@cert-authority ecdsa-sk', :'@cert-authority [email protected]')
aliasvalue(:'@cert-authority ed25519-sk', :'@cert-authority [email protected]')
end

newproperty(:key) do
Expand Down
66 changes: 66 additions & 0 deletions spec/integration/provider/sshkey_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,70 @@
resource_app.main
end
end

describe 'cert-authority functionality' do
let(:provider_class) { described_class }
let(:type) { Puppet::Type.type(:sshkey) }

describe 'round-trip conversion' do
it 'correctly parses and generates cert-authority entries' do
# Test parsing a cert-authority line
line = '@cert-authority *.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzwHhxXvIrtfIwrudFqc8yQcIfMudrgpnuh1F3AV6d2BrLgu/yQE7W5UyJMUjfj427sQudRwKW45O0Jsnr33F4mUw+GIMlAAmp9g24/OcrTiB8ZUKIjoPy/cO4coxGi8/NECtRzpD/ZUPFh6OEpyOwJPMb7/EC2Az6Otw4StHdXUYw22zHazBcPFnv6zCgPx1hA7QlQDWTu4YcL0WmTYQCtMUb3FUqrcFtzGDD0ytosgwSd+JyN5vj5UwIABjnNOHPZ62EY1OFixnfqX/+dUwrFSs5tPgBF/KkC6R7tmbUfnBON6RrGEmu+ajOTOLy23qUZB4CQ53V7nyAWhzqSK+hw=='

# Parse the line
parsed = provider_class.parse_line(line)
expect(parsed[:name]).to eq('*.example.com')
expect(parsed[:type]).to eq('@cert-authority ssh-rsa')
expect(parsed[:key]).to start_with('AAAAB3NzaC1yc2EA')

# Test generating back to line format
generated_line = provider_class.to_line(parsed)
expect(generated_line).to eq(line)
end

it 'handles cert-authority entries with host aliases' do
line = '@cert-authority *.example.com,*.test.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzwHhxXvIrtfIwrudFqc8yQcIfMudrgpnuh1F3AV6d2BrLgu/yQE7W5UyJMUjfj427sQudRwKW45O0Jsnr33F4mUw+GIMlAAmp9g24/OcrTiB8ZUKIjoPy/cO4coxGi8/NECtRzpD/ZUPFh6OEpyOwJPMb7/EC2Az6Otw4StHdXUYw22zHazBcPFnv6zCgPx1hA7QlQDWTu4YcL0WmTYQCtMUb3FUqrcFtzGDD0ytosgwSd+JyN5vj5UwIABjnNOHPZ62EY1OFixnfqX/+dUwrFSs5tPgBF/KkC6R7tmbUfnBON6RrGEmu+ajOTOLy23qUZB4CQ53V7nyAWhzqSK+hw=='

parsed = provider_class.parse_line(line)
expect(parsed[:name]).to eq('*.example.com')
expect(parsed[:host_aliases]).to eq(['*.test.com'])
expect(parsed[:type]).to eq('@cert-authority ssh-rsa')

# Test generating back
generated_line = provider_class.to_line(parsed)
expect(generated_line).to eq(line)
end
end

describe 'resource creation' do
it 'can create a cert-authority sshkey resource' do
expect {
type.new(
name: '*.example.com',
type: '@cert-authority ssh-rsa',
key: 'AAAAB3NzaC1yc2EAAAA'
)
}.not_to raise_error
end

it 'can create a cert-authority resource with aliases' do
expect {
type.new(
name: '*.example.com',
type: '@cert-authority rsa', # Test alias
key: 'AAAAB3NzaC1yc2EAAAA'
)
}.not_to raise_error
end

it 'aliases cert-authority key types correctly' do
resource = type.new(
name: '*.example.com',
type: '@cert-authority rsa', # Alias
key: 'AAAAB3NzaC1yc2EAAAA'
)
expect(resource[:type]).to eq(:'@cert-authority ssh-rsa')
end
end
end
end
14 changes: 14 additions & 0 deletions spec/unit/provider/sshkey/parsed_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ def key
expect(subject.parse_line('test ssh-rsa ' + key)[:host_aliases]).to eq([])
end

it 'parses cert-authority entries correctly' do
result = subject.parse_line('@cert-authority *.example.com ssh-rsa ' + key)
expect(result[:name]).to eq('*.example.com')
expect(result[:type]).to eq('@cert-authority ssh-rsa')
expect(result[:key]).to eq(key)
end

it 'parses cert-authority entries with host aliases' do
result = subject.parse_line('@cert-authority *.example.com,*.test.com ssh-rsa ' + key)
expect(result[:name]).to eq('*.example.com')
expect(result[:host_aliases]).to eq(['*.test.com'])
expect(result[:type]).to eq('@cert-authority ssh-rsa')
end

context 'with the sample file' do
['sample', 'sample_with_blank_lines'].each do |sample_file|
let(:fixture) { my_fixture(sample_file) }
Expand Down
25 changes: 24 additions & 1 deletion spec/unit/type/sshkey_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@
:'ecdsa-sha2-nistp521',
:'ssh-ed25519', :ed25519,
:'ecdsa-sk', :'[email protected]',
:'ed25519-sk', :'[email protected]'
:'ed25519-sk', :'[email protected]',
:'@cert-authority ssh-dss', :'@cert-authority dsa',
:'@cert-authority ssh-rsa', :'@cert-authority rsa',
:'@cert-authority ecdsa-sha2-nistp256',
:'@cert-authority ecdsa-sha2-nistp384',
:'@cert-authority ecdsa-sha2-nistp521',
:'@cert-authority ssh-ed25519', :'@cert-authority ed25519',
:'@cert-authority ecdsa-sk', :'@cert-authority [email protected]',
:'@cert-authority ed25519-sk', :'@cert-authority [email protected]'
].each do |keytype|
it "supports #{keytype} as a type value" do
described_class.new(name: 'foo', type: keytype)
Expand All @@ -56,6 +64,21 @@
expect(key.parameter(:type).value).to eq :'[email protected]'
end

it 'aliases :@cert-authority rsa to :@cert-authority ssh-rsa' do
key = described_class.new(name: 'foo', type: :'@cert-authority rsa')
expect(key.parameter(:type).value).to eq :'@cert-authority ssh-rsa'
end

it 'aliases :@cert-authority dsa to :@cert-authority ssh-dss' do
key = described_class.new(name: 'foo', type: :'@cert-authority dsa')
expect(key.parameter(:type).value).to eq :'@cert-authority ssh-dss'
end

it 'aliases :@cert-authority ed25519 to :@cert-authority ssh-ed25519' do
key = described_class.new(name: 'foo', type: :'@cert-authority ed25519')
expect(key.parameter(:type).value).to eq :'@cert-authority ssh-ed25519'
end

it "doesn't support values other than ssh-dss, ssh-rsa, dsa, rsa for type" do
expect {
described_class.new(name: 'whev', type: :'ssh-dsa')
Expand Down