I want to run a command in open source puppet to activate a Unity3D license, but I don't want the serial or the password in my git repo:
exec { 'license-unity':
command => '/opt/Unity/Editor/Unity -batchmode -nographics -serial A1-ABCD-1234-ETC -username my.user#a.b.ca -password myPassword -quit'
subscribe => Package['UnityEditor'],
refreshonly => true,
}
How can I read the serial# and the password from a file (either on the puppetserver or on the node) and substitute it in the command?
For example, if I had a file on the puppet server called .secret owned by root and perms 400. How do I read the content into a variable for use in the puppet manifest?
There are two standard ways to achieve this given the route you prefer:
Use the file function. This is for masterless Puppet or the file is hosted on the Puppet Master.
# using the module path instead of the absolute path would end up storing your secret in git, which is what you are trying to avoid
$password = file('/absolute/path/to/.secret')
exec { 'license-unity':
command => "/opt/Unity/Editor/Unity -batchmode -nographics -serial A1-ABCD-1234-ETC -username my.user#a.b.ca -password $password -quit"
subscribe => Package['UnityEditor'],
refreshonly => true,
}
Doc: https://puppet.com/docs/puppet/5.3/function.html#file
Corollary: If you need to do some kind of parsing on the file, such as if it is more than a text file with the password inside, then you can use a custom function with the modern Ruby API. https://puppet.com/docs/puppet/5.3/functions_ruby_overview.html. Let me know if this is the case.
Use a custom fact. This is for storing the file on the client in a Master/Client setup. Using an external fact would also end up storing the secret in git, which would present the problem you are attempting to avoid.
# module/lib/facter/password.rb
Facter.add(:password) do
setcode do
File.read('/absolute/path/to/.secret')
end
end
# manifest.pp
exec { 'license-unity':
command => "/opt/Unity/Editor/Unity -batchmode -nographics -serial A1-ABCD-1234-ETC -username my.user#a.b.ca -password $password -quit"
subscribe => Package['UnityEditor'],
refreshonly => true,
}
Doc: https://puppet.com/docs/facter/3.9/custom_facts.html#configuring-facts
Corollary: If you need to do some kind of parsing on the file, such as if it is more than a text file with the password inside, then you can use native Ruby classes and methods for that (i.e. JSON.parse or YAML.load_file if the file is in those formats).
Notable alternatives to the method you are pursuing include using Puppet to retrieve from a secrets management software, such as Vault, or using encryption/decryption algorithms, such as AES-256, to store the encrypted file in your SCM and then decrypt it during catalog compilation.
I am trying to automate the process of adding extra storage in a linux machine. I'm using plink in PowerShell installed on my Windows machine.
Below is the code:
$plinkpath = "C:\Users\mydrive\Modules\plink.exe"
if (Test-Path $plinkpath) {
Set-Alias plink $plinkpath
} else {
throw "Plink.exe is reqruied"
}
$passw = "linuxadmin$123"
$commands = #(
"sudo su;",
"pvcreate /dev/sde;",
"vgcreate test_vog /dev/sde",
"lvcreate -l 100%FREE -n test_lev test_vog;",
"mkfs.ext3 /dev/test_vog/test_lev;",
"mkdir /azurenew;",
"echo ""/dev/test_vog/test_lev /azurenew/ ext3 defaults 1 1"" >> /etc/fstab;",
"mount /azurenew/;"
)
Approach 1: Using .ppk file
plink -ssh -i "C:\Users\amurthy\Documents\WindowsPowerShell\Modules\sshprivate.ppk" linuxadmin#xx.xx.xx.xxx $commands
In the above situation PowerShell hangs and no response on the console. Not sure what's happening.
Approach 2: using direct log in
plink -P "22" -v "linuxadmin#xx.xx.xx.xxx" -pw "linuxadmin$123" $commands
Here, I get below response on console
Using username "linuxadmin".
Sent password
Password authentication failed
I do not understand why the passoword authentication failed though I am able to login using putty.exe with that password.
Can anyone please help me here to solve my above automation problem? If you have any better solution altogether really welcome.
The password login attempt fails because you defined the password in a double-quoted string. PowerShell tries to expand the (undefined) variable $123 in linuxadmin$123, so you're actually passing just linuxadmin as the password. You could use a single-quoted string to avoid this, but public key authentication (your first approach) is the better approach anyway, so I recommend sticking with that.
I'm not sure why your first approach causes the console to hang, though. If the key were password-protected you should be prompted for the password. There's a semicolon missing at the end of "vgcreate test_vog /dev/sde", but if that caused an issue I'd expect to see an error message.
Try running plink with the parameter -v (verbose messages) to get a better picture of what's going on.
As we know that a curl request for a url that is protected by basic authentication can be made by using a format like this curl -v http://username: password#xyz.com . But i have observed that passing credentials like this only works if password does not have a "#" itself. For example If my request is curl -v http://user01:helloworld#xyz.com it will work . But if it is curl -v http://user01:hello#world#xyz.com , it fails . How can we make the first # to be understood as a password, as currently i think # is taken as a conventional delimiter before passing credentials, and therefore request gets confused as to what is the password . Any thoughts on this, or am i missing anything ?
Use -u which defaults to basic auth
-u, --user <user:password>
Specify the user name and password to use for server authentication. Overrides -n, --netrc and --netrc-
optional.
If you simply specify the user name, curl will prompt for a password.
The user name and passwords are split up on the first colon, which makes it impossible to use a colon in
the user name with this option. The password can, still.
Possibly even better would be to define your passwords in the netrc file and then avoid passwords on the command line altogether.
I need to create a test user with a password using puppet.
I've read that puppet cannot manage user passwords in a generic cross-platform way, which is a pity.
I am doing this for Red Hat Enterprise Linux Server release 6.3.
I do as follows:
user { 'test_user':
ensure => present,
password => sha1('hello'),
}
puppet updates the password of the user,
but Linux says login/pwd incorrect when I try to log in.
It works (I can login) if I set the password manually in Linux with sudo passwd test_user, and then look at /etc/shadow and hardcode that value in puppet. something like:
user { 'test_user':
ensure => present,
password => '$1$zi13KdCr$zJvdWm5h552P8b34AjxO11',
}
I've tried also by adding $1$ in front of the sha1('hello'),
but it does not work either (note, $1$ stands for sha1).
How to modify the first example to make it work (using the plaintext password in the puppet file)?
P.S.: I am aware that I should use LDAP, or sshkeys, or something else, instead of hardcoding the user passwords in the puppet file. however, I am doing this only for running a puppet vagrant test, so it is ok to hardcode the user password.
Linux users have their passwords stored as hash in /etc/shadow file. Puppet passes the password supplied in the user type definition in the /etc/shadow file.
Generate your hash password using openssl command:
#openssl passwd -1
#Enter your password here
Password:
Verifying - Password:
$1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM
The previous example generate this hash:
$1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM/
Add this hash password to your class as shown (do not forget the quotes)
user { 'test_user':
ensure => present,
password => '$1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM/',
}
The stdlib package of puppetlabs implements a similar pw_hash function of the accepted answer.
Be sure to add the library to your configuration. If you use librarian, just add in your Puppetfile
mod 'puppetlabs-stdlib'
Then to create an user, simply :
user { 'user':
ensure => present,
password => pw_hash('password', 'SHA-512', 'mysalt'),
}
The sha1 function in puppet is not directly intended for passwd entries, as you figured out.
I'd say setting the hash rather than the password is good practice! You are not really supposed to be able to recover a password anyway - you can generate it once, or you can have puppet generate it every time - generating that hash once should be enough IMHO...
You can generate a password on Debian/Ubuntu like this:
pwgen -s -1 | mkpasswd -m sha-512 -s
...on CentOS you can use some grub-crypt command instead of mkpasswd...
I had success (gist) with ruby's String#crypt method from within a Puppet parser function.
AFAICS it's using the crypt libc functions (see: info crypt), and takes the same arguments $n$[rounds=<m>$]salt, where n is the hashing function ($6 for SHA-512) and m is the number of key strengthening rounds (5000 by default).
You can use the generate function to let Puppet create the hash for you:
$password = 'hello'
user { 'test_user':
ensure => 'present',
password => generate('/bin/sh', '-c', "mkpasswd -m sha-512 ${password} | tr -d '\n'"),
}
Puppet: user with a SHA 512 hashed password
I came up with a method that doesn't need anything to add if you have python 2.6. I tested this on puppet 3.6.2 on CentOS 6.4:
$pass="password"
$shatag="\$6\$"
$cmd="import crypt, base64, os, sys; sys.stdout.write(crypt.crypt('$pass', '$shatag' + base64.b64encode(os.urandom(16))[:8]))"
user { 'boop':
ensure => present,
password => generate ("/usr/bin/python", "-c", $cmd),
}
Explanations
the sha tag is here to specify to crypt the hash method we want:
6 is the type of hash for SHA-512
$1$ -> MD5
$2a$ -> Blowfish (not in mainline glibc; added in some Linux distributions)
$5$ -> SHA-256 (since glibc 2.7)
$6$ -> SHA-512 (since glibc 2.7)
thx davey and wiki_crypt
sys.stdout.write is here to avoid '\n' of print
base64.b64encode(os.urandom(16))[:8]):
os.urandom(16) create a 16 bits long binary string
base64.b64encode encode this string in base64
[:8] take the first 8 characters of this string (as base64 encoding length may vary)
generate is a puppet function that create text when on the puppet master.
You can't use this function like you want because it is 'protected' ê.é (last post suggest a workaround to this protection-or-whatever)
hth
In my Vagrantfile, I did this:
$newuserid = ENV["USERNAME"]
config.vm.provision :puppet do |puppet|
puppet.module_path = "modules"
puppet.manifests_path = "manifests"
puppet.manifest_file = "main.pp"
puppet.facter = {"newuserid" => $newuserid}
puppet.options = "--verbose"
end
And in my main.pp file:
user { $newuserid :
ensure => present,
home => "/home/${newuserid}",
managehome => true,
gid => "mygid",
}
exec { 'set password':
command => "/bin/echo \"${newuserid}:${newuserid}\" | /usr/sbin/chpasswd",
require => User [ $newuserid ],
}
just generate encrypted password from grub-crypt --sha-512 and paste
I have a client and server system that regularly run scheduled tasks and communicate through xml files that have been encrypted by gpg. All required public keys have been successfully exchanged between the client and server. The encryption and decryption calls are being done from a batch file.
encrypt syntax
gpg.exe --batch --yes --recipient %1 --output %4 --passphrase %5 --local-user %2 --sign --encrypt %3
decrypt syntax
gpg.exe --batch --yes --output %3 --passphrase %4 --decrypt %2 2>%1
The client creates a xml file, encrypts it with gpg using server public key, signs with private key and uploads it to the server's ftp site. Server regularly checks for new files in ftp folder. For any new file it decrypts using gpg and then processes the xml inside the file.
For some of the xml files that the server tries to decrypt, I receive an error as follows:
gpg: block_filter 00AA8400: read error (size=7841,a->size=395)
gpg: mdc_packet with invalid encoding
gpg: decryption failed: invalid packet
gpg: block_filter: pending bytes!
The point to note is that this is not happening with all the files but with only some files. I haven't been able to find any commonality between the files that it fails on.
Is anyone familiar to what this error means? any suggestions to help track this down are welcome.
Finally figured it out. gpg was not the culprit here. when the server was checking for files in the specified folder, it was using the Append(fileHandler) method on Delphi to test if the file could be opened. But this method had a peculiar condition as if it found the ascii character 26 (i.e. CTRL+z) in the last 128 byte block of the file, it would remove everything from that character till the end of the file. This caused some part of the encrypted files to be deleted and subsequently caused the above error when decrypting it through gpg. After I replaced the Append method with Reset(fileHandler), encrypted files were no longer modified and decryption works perfectly.