Reputation: 382
I started to learn Puppet this week and trying hard to implement user's keys to /etc/ssh/sudo_authorized_keys
.
I have a dictionary of users with keys in sudo_users.yaml
:
core::sudo_users_keys:
kate:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3N..."
john:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC..."
marvin:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3Nza..."
Then I create this in sudokeys.pp
file:
class core::sudokeys {
file { "/etc/ssh/sudo_authorized_keys":
ensure => file,
mode => "0440",
content => template("core/sudo_authorized_keys.erb"),
}
As you can see, I want to implement template with iteration. This is my current template:
<%- scope['core::sudo_users_keys'].each | user | -%>
{
<%- if user[1] -%>
<%- $user[1]['keys'].each do | key | -%>
<%= $key[1]['type'] $key[1]['key'] -%>
<%- end end -%>
}
<%- end -%>
I have the same dictionary with id_rsa keys to ssh and use interaction as below.
It works perfectly for ssh_authorized_key, but I can use it in this case by adding keys to /etc/ssh/sudo_authorized_keys
. That's why I decided to use a template and only inject keys inside the sudo_authorized_keys
file.
class core::sshkeys {
lookup("core::sudo_users_keys").each | $user | {
if $user[1] {
$user[1]["keys"].each | $key | {
ssh_authorized_key { "${user[0]}-${key[0]}":
ensure => present,
user => $user[0],
type => $key[1]["type"],
key => $key[1]["key"],
}
}
}
}
}
Puppet documentation doesn't include this kind of more complicated iterations and I feel like wandering in the fog.
Currently, I'm getting this error when deploying my template, but I feel like the way I prepare this will not work as I wanted.
Internal Server Error: org.jruby.exceptions.SyntaxError: (SyntaxError) /etc/puppetlabs/code/environments/test/modules/core/templates/sudo_authorized_keys.erb:2: syntax error, unexpected tSTRING_BEG
_erbout.<< " {\n".freeze
^
I will appreciate any suggestions about template construction. What should I change to make it work and extract only type
and key
values?
Upvotes: 0
Views: 329
Reputation: 382
I used John Bollinger answer, however template wasn't perfect in my case, because I was constantly getting errors like eg. syntax error, unexpected end-of-file _erbout
.
The proper sudo_authorized_keys.erb file that worked for me is this one:
<%- @users_keys.each do | user, config | -%>
<%- if config.has_key?('keys') -%>
<%- config['keys'].each do | name, value | -%>
<%= value['type'] %> <%= value['key'] %> <%= user %>
<%- end -%>
<%- end -%>
<%- end -%>
Upvotes: 0
Reputation: 180093
Your approach is workable, but there are multiple issues with your code, among them
the scope
object in a template provides access to Puppet variables, not to Hiera data. Probably the easiest way to address that would be to
core::sudokeys
class a class parameter to associate with the data ($userkeys
, say),scope
object in that case).in the template, you seem to be assuming a different structure for your data than it actually has in Hiera. Your data is a hashes of hashes of hashes, but you are accessing parts of it as if there were arrays involved somewhere (user[1]
, key[1]
). Also, if there were one or more arrays, then do be aware that Ruby array indexes start at 0, not at 1.
Scriptlet code in an ERB template is (only) Ruby. Your scriptlet code appears to mix Ruby and Puppet syntax. In particular, Ruby variable names are not prefixed with a $
, and Ruby block parameters appear inside the block, not outside it.
<%= ... %>
tags a for outputting the value of one Ruby expression each. You appear to be trying to emit multiple expressions with the same tag.
Also, it's worth noting that scriptlet code can span multiple lines. That can make it clearer. Additionally, you may need to pay attention to whitespace and newlines in your template to get the output you want. ERB has options to consume unwanted whitespace around scriptlet tags, if needed, but sometimes its at least as easy to just avoid putting in whitespace that you don't want. On the other hand, be sure not to suppress whitespace that you actually wanted.
So, here's one form that all of the above might take:
sudo_users.yaml
core::sudokeys::users_keys:
kate:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3N..."
john:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC..."
marvin:
keys:
key1:
type: "ssh-ed25519"
key: "AAAAC3Nza..."
sudokeys.pp
class core::sudokeys($users_keys) {
file { "/etc/ssh/sudo_authorized_keys":
ensure => file,
mode => "0440",
content => template("core/sudo_authorized_keys.erb"),
}
}
sudo_authorized_keys.erb
<% @users_keys.each do | user |
if user.has_key?('keys') do
user['keys'].each do |key|
%><%= key['type'] %> <%= key['key'] %>
<% # don't consume preceding whitespace here
end
end
end
%>
Upvotes: 1