“Chef is used to streamline the task of configuring and maintaining a company’s servers, and can integrate with cloud-based platforms such as Internap, Amazon EC2, Google Cloud Platform, OpenStack, SoftLayer, Microsoft Azure and Rackspace to automatically provision and configure new machines.” – From Wikipedia
This article is about the REST APIs by Chef which provide access to Chef server, nodes, users, organizations, permissions, keys etc. Refer – Chef Server API
When a node is configured with chef-client, a Public and Private Key pair is generated. Public Key is stored on the Chef server while the Private Key is returned to the user/client. This key pair is used for creating a trust between the server and the client for authenticating the requests.
All the Chef API requests should have a set of HTTP Headers signed using the Private Key associated with the server. The Chef server can verify the signature using the Public Key stored on the server. (Refer – Chef Auth)
For beginners like me, its not easy to integrate these APIs with java code due to the complex HTTP Headers that need to be generated and sent with every request. After trying few solutions from Github, finally was able to successfully get through the Authentication and make API calls.
Download the working Java code – Download Zip
This code takes username, private key path (.pem file) and Chef Server host as input.
Main Class – APIMain
Referred Github project – Link
Understanding Authentication
// The canonical header is framed below StringBuilder sb = new StringBuilder(); sb.append("Method:").append(methodName).append("\n"); sb.append("Hashed Path:").append(hashedPath). append("\n"); sb.append("X-Ops-Content-Hash: ").append(hashedBody).append(" \n"); sb.append("X-Ops-Timestamp:"). append(timeStamp).append("\n") ; sb.append("X-Ops-UserId:"). append(userId);
//It is then signed with the private key String auth_String = Utils.signWithRSA(sb.toString(), pemPath);
// Split in 60 length substrings and set in an array String[] auth_headers = Utils.splitAs60(auth_String);
//The main header values are set method.addRequestHeader("Content-type", "application/json"); method.addRequestHeader("X- Ops-Timestamp", timeStamp); method.addRequestHeader("X- Ops-Userid", userId); method.addRequestHeader("X- Chef-Version", "0.10.4"); method.addRequestHeader(" Accept", "application/json"); method.addRequestHeader("X- Ops-Content-Hash", hashedBody); method.addRequestHeader("X- Ops-Sign", "version=1.0"); // The Substrings of 60 each are set in the X-Ops0Authorization-1,2.. header for (int i = 0; i < auth_headers.length; i++) { method.addRequestHeader("X- Ops-Authorization-" + (i + 1), auth_headers[i]); }
//Method call is made
code = client.executeMethod(method);
Possible Errors
- If the Chef Server instance is running on HTTPS without a valid SSL certificate then the HTTP Client will throw below Error-
(PKIX path building failed: sun.security.provider.certpath. SunCertPathBuilderException)
This error is due to SSL Handshake failure between the HTTP Client and the Chef Server.
The solution is to install a valid SSL certificate. (by configuring a Load Balancer and SSL cert with it or importing the certificate in the java keystore file)
- If the Chef Server instance is running on HTTPS with a self signed certificate, then the same CA certificate needs to be imported to the java keystore of machine from where request is being made. (HTTP Client)
Follow this article to see how to import SSL cert to keystore- Link
Thanks for checking out. Let us know through comments or contact us section in case of any issues.
- Monitor Kubernetes Control Plane Services Availability with Heartbeat [ELK] - December 14, 2020
- Setup and operate ELK Stack on Kubernetes cluster using Argo CD - October 26, 2020
- Auto clear notification using Watcher - June 10, 2020