Puppet Enterprise DB API and Structured Facts

You are here: Home » AWS » Puppet Enterprise DB API and Structured Facts

 

For a recent project I was challenged with the need to prove an AWS EC2 instance was a puppet server without access to the instance. Thankfully Puppet Enterprise DB API has exactly what I needed. However I found the examples in the documentation online where not good enough for my needs.

Here is a shell script example using cURL to get the puppet certname when you only know the EC2 instanceID string:

export CERT=/etc/puppetlabs/puppet/ssl/certs/<NODE>.pem
export CACERT=$(puppet master --configprint localcacert)
export PRVKEY=/etc/puppetlabs/puppet/ssl/private_keys/<NODE>.pem
export CERT_OPTIONS="--cert ${CERT} --cacert ${CACERT} --key ${PRVKEY}"
export DBAPI="https://puppet.bryanandrews.org:8081"

# working - example of getting the certname by ec2 instance-id structured fact
curl -v -k -X GET -H "Accept: application/json" ${CERT_OPTIONS} \
${DBAPI}/pdb/query/v4/fact-contents \
--data-urlencode 'query=["and", ["=", "path", ["ec2_metadata", "instance-id"]], ["=", "value", "i-325fe2e9"]]'

# Result:
#[ {
# "certname" : "taco-puppet-1.bryanandrews.local",
# "environment" : "dev",
# "name" : "ec2_metadata",
# "path" : [ "ec2_metadata", "instance-id" ],
# "value" : "i-325fe2e9"
#} ]

From this I was able to use what I learned and perform the same query in PHP. Before this works you need to make sure the SSL cert you are using to make the request is in the puppetDB whitelist file at /etc/puppetlabs/puppetdb/certificate-whitelist on the puppetDB server.

$iid = “i-325fe2e9”; // get this instance ID, if it exists

define(‘PUPPETDB_URL’,’https://puppet.bryanandrews.org:8081′);
$query = ‘[“and”, [“=”, “path”, [“ec2_metadata”, “instance-id”]], [“=”, “value”, “‘.$iid.'”]]’;
$query = ‘query=’.urlencode($query);
$url = PUPPETDB_URL.”/pdb/query/v4/fact-contents”;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(‘Accept: application/json’, ‘Accept: s’, ‘Content-Type: application/x-www-form-urlencoded’));
//curl_setopt($ch, CURLOPT_POST, 1); // nope, even though we are posting we need this to use GET
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, “GET”); // puppetDB requires GET method
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // TRUE to return the transfer as a string of the return value of curl_exec()
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // 0: Don’t check the common name (CN) attribute
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSLKEY, PUPPETDB_KEY); // define points to the agents SSL KEY file
curl_setopt($ch, CURLOPT_SSLCERT, PUPPETDB_CERT); //define points to the agents SSL CRT file
curl_setopt($ch, CURLOPT_CAINFO, PUPPETDB_CA); // define points to the PE CA CRT file

$response = curl_exec($ch);

if (curl_errno($ch)){
print “curl error: “.curl_error($ch);
print “curl error details: “.print_r(curl_getinfo($ch), TRUE);
// return or exit
}

$info = curl_getinfo($ch);
$HTTPcode = $info[‘http_code’]; // Example: 200

curl_close($ch);

if (($response != “”) && ($HTTPcode == 200) ) {

$array = json_decode($response, TRUE); // json string to assoc array

if (is_array($array)) {
$certname = $array[‘0’][‘certname’]; // found it
}