by Gary Pennington and Glynn Foster
Learn how to configure an Oracle Solaris 11.3 system to provide secure administration over the new REST APIs using the Oracle Solaris Remote Administration Daemon (RAD).
Introduction
One of the new enhancements included in Oracle Solaris 11 is the Remote Administration Daemon (also known as RAD). RAD provides a set of programmatic interfaces to allow administrators to manage Oracle Solaris 11 subsystems such as Oracle Solaris Zones, the ZFS file system, the Service Management Facility (SMF), and more. A previous article, "Getting Started with the Remote Administration Daemon on Oracle Solaris 11," covered how to use RAD using C, Python, Java, and REST programmatic interfaces. This article shows administrators how they can configure an Oracle Solaris 11.3 system to enable REST-based calls over HTTPS using the Transport Layer Security (TLS) protocol.
RAD REST Bindings
In Oracle Solaris 11.3, a new REST interface to RAD has been added. REST APIs are an increasingly popular way of interacting with system services across the network over both HTTP and HTTPS using an encoding payload such as JSON or XML. Oracle Solaris 11.3 includes a new SMF service instance, svc:/system/rad:local-http
, that is responsible for facilitating RAD communication from HTTP clients. Given that HTTP connections are not encrypted, the default configuration allows only for accepting connections from a local host on a UNIX socket. With a little configuration, administrators can open up a public port and provide secure transport over TLS.
Creating a New RAD Service Instance
The first step we need to do is to configure RAD to accept connections from a remote host over HTTP. In Oracle Solaris 11.3, there are currently three SMF service instances that are responsible for handling RAD connections:
- The
svc:/system/rad:local
service instance manages local connections through UNIX sockets.
- The
svc:/system/rad:remote
service instance manages secure remote TLS connections over TCP sockets.
- The
svc:/system/rad:local-http
service instance provides access for local connections over HTTP.
At the time of this writing, there is no system-provided service instance to manage secure remote connections over HTTP, so we need to create one—it is likely that one will be provided in a future release of Oracle Solaris.
To do this, we need to create an SMF manifest. There are a number of ways to achieve this—either by taking a copy of the existing /lib/svc/manifest/system/rad.xml
manifest and modifying it, or by using svcbundle
(1M) to generate one and refining it afterwards. The key elements that the service instance needs to expose relate to key and certificate handling (using the PEM format common for most certificate authorities), the port to accept connections from, and the RAD protocol being used.
For convenience, the full SMF manifest is provided below:
# cat rad-remote-http.xml
<?xml version="1.0" ?>
<!DOCTYPE service_bundle
SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type="manifest" name="site/rad">
<service version="1" type="service" name="site/rad">
<dependency restart_on="none" type="service"
name="multi_user_dependency" grouping="require_all">
<service_fmri value="svc:/milestone/multi-user"/>
</dependency>
<exec_method name='start' type='method' exec='/usr/lib/rad/rad -sp' timeout_seconds='0'/>
<exec_method name='stop' type='method' exec=':kill' timeout_seconds='0'/>
<instance name='remote-http' enabled='false' complete='true'>
<property_group name='ssl_port' type='xport_tls'>
<propval name='certificate' type='astring' value='/etc/rad/cert.pem'/>
<propval name='generate' type='boolean' value='true'/>
<propval name='localonly' type='boolean' value='false'/>
<propval name='pam_service' type='astring' value='rad-tls'/>
<propval name='port' type='integer' value='12303'/>
<propval name='privatekey' type='astring' value='/etc/rad/key.pem'/>
<propval name='proto' type='astring' value='rad_http'/>
<propval name='value_authorization' type='astring' value='solaris.smf.value.rad'/>
</property_group>
<property_group name='config' type='application'>
<property name='moduledir' type='astring'>
<astring_list>
<value_node value='/usr/lib/rad/transport'/>
<value_node value='/usr/lib/rad/protocol'/>
<value_node value='/usr/lib/rad/module'/>
<value_node value='/usr/lib/rad/site-modules'/>
</astring_list>
</property>
</property_group>
</instance>
<template>
<common_name>
<loctext xml:lang="C">Remote RAD HTTP</loctext>
</common_name>
<description>
<loctext xml:lang="C">RAD connections over REST (HTTP)</loctext>
</description>
</template>
</service>
</service_bundle>
From the SMF manifest above, we have created a new SMF instance at svc:/site/rad:remote-http
. We can see that the start method will call the /usr/lib/rad/rad
daemon. We also include a number of properties within the ssl_port
property group: certificate
and privatekey
provide credentials we need to make a secure connection over HTTPS (RAD will automatically generate these using self-signed certificates), port
defines the port number on which to accept connections and is set to 12303
, and proto
defines that the RAD protocol to use is HTTP (as indicated by rad-http
).
The next step is to copy the manifest to our site-wide SMF manifest location, /lib/svc/manifest/site
, and restart the svc:/system/manifest-import:default
service instance:
root@solaris:~# cp rad-remote-http.xml /lib/svc/manifest/site
root@solaris:~# svcadm restart manifest-import
root@solaris:~# svcadm enable rad:remote-http
root@solaris:~# svcs rad:remote-http
STATE STIME FMRI
online 17:46:59 svc:/site/rad:remote-http
If we now try to make a simple request to [https://](/)<hostname>:12303
using a web browser, we will get back the following snippet of JSON:
{
"status": "illegal access",
"payload": {
"Message": "Response content type 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' requested
yet only 'application/json' is supported by the origin server.",
"HTTP Method": "GET",
"URI": "/",
"RAD Operation": null
}
}
From the output above, we can see that we're connecting to a valid port with a RAD server on the back end, and it accepts only application/json
as input.
Setting up a RAD Connection
As detailed in "Getting Started with the Remote Administration Daemon on Oracle Solaris 11," we need to set up the RAD connection. As before, we'll send a POST request to the /api/com.oracle.solaris.rad.authentication/1.0/Session
API, and we'll also provide some credentials included in a JSON file called body.json
, as follows:
{
"username": "root",
"password": "solaris11",
"scheme": "pam",
"preserve": true,
"timeout": -1
}
We can now use curl
(1) with a slightly different set of command-line options that point to our SSL key and certificate pair (which we have copied over to the system from where we are making the RAD queries), saving the authentication token to a file called cookie.txt
:
# curl -H "Content-type: application/json" -X POST \
--data-binary @body.json \
--cert solaris-cert.pem --key solaris-key.pem -k \
https://solaris.us.oracle.com:12303/api/com.oracle.solaris.rad.authentication/1.0/Session \
-v -c cookie.txt -b cookie.txt
* Trying 10.134.79.148...
* Failed to set TCP_KEEPALIVE on fd 4
* Connected to solaris.us.oracle.com (10.134.79.148) port 12303 (#0)
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/openssl/certs
* TLSv1.2, TLS handshake, Client hello (1):
* TLSv1.2, TLS handshake, Server hello (2):
* TLSv1.2, TLS handshake, CERT (11):
* TLSv1.2, TLS handshake, Server finished (14):
* TLSv1.2, TLS handshake, Client key exchange (16):
* TLSv1.2, TLS change cipher, Client hello (1):
* TLSv1.2, TLS handshake, Finished (20):
* TLSv1.2, TLS change cipher, Client hello (1):
* TLSv1.2, TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
* Server certificate:
* subject: CN=Remote Administration Daemon @ dcsw-79-148
* start date: 2015-07-26 23:35:37 GMT
* expire date: 2025-07-23 23:35:37 GMT
* issuer: CN=Remote Administration Daemon @ dcsw-79-148
* SSL certificate verify result: self signed certificate (18), continuing anyway.
> POST /api/com.oracle.solaris.rad.authentication/1.0/Session HTTP/1.1
> User-Agent: curl/7.40.0
> Host: solaris.us.oracle.com:12303
> Accept: */*
> Content-type: application/json
> Content-Length: 128
>
* upload completely sent off: 128 out of 128 bytes
< HTTP/1.1 201 Created
< Connection: Keep-Alive
< Content-Length: 164
< Expires: 0
< Pragma: no-cache
< Cache-Control: no-cache, no-store, must-revalidate
< Location: /api/com.oracle.solaris.rad.authentication/1.0/Session/_rad_reference/3328
* Added cookie _rad_instance="3328" for domain solaris.us.oracle.com, path /api, expire 1437962830
< Set-Cookie: _rad_instance=3328; Path=/api; Max-Age=3600; HttpOnly
* Added cookie _rad_token="613891db-9cd8-44fe-90a2-d6d8d94c2fb3" for
domain solaris.us.oracle.com, path /api, expire 1437962830
< Set-Cookie: _rad_token=613891db-9cd8-44fe-90a2-d6d8d94c2fb3;
Path=/api; Max-Age=3600; HttpOnly
< Date: Mon, 27 Jul 2015 00:59:48 GMT
<
{
"status": "success",
"payload": {
"href": "/api/com.oracle.solaris.rad.authentication/1.0/Session/_rad_reference/3328"
}
* Connection #0 to host solaris.us.oracle.com left intact
}
We can examine the cookie that has been created:
# cat cookie.txt
# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_solaris.us.oracle.com FALSE /api FALSE 1437962830 _rad_instance 3328
#HttpOnly_solaris.us.oracle.com FALSE /api FALSE 1437962830 _rad_token 613891db-9cd8-44fe-90a2-d6d8d94c2fb3
Querying Oracle Solaris Zones
Now that we have our connection token, we can query the system. For example, we will use the /api/com.oracle.solaris.rad.zonemgr/1.0/Zone
API to query the zones that have been configured on our host:
# curl -H "Content-type: application/json" -X GET \
--cert solaris-cert.pem --key solaris.pem -k \
https://solaris.us.oracle.com:12303/api/com.oracle.solaris.rad.zonemgr/1.0/Zone -b cookie.txt
{
"status": "success",
"payload": [
{
"href": "api/com.oracle.solaris.rad.zonemgr/1.2/Zone/zone1"
}
]
}
From the output above, we can see that we have a single zone called zone1
. This is confirmed by running zoneadm
(1M) from the host directly:
root@solaris:~# zoneadm list -cv
ID NAME STATUS PATH BRAND IP
0 global running / solaris shared
- zone1 configured /system/zones/zone1 solaris excl
Summary
The Oracle Solaris Remote Administration Daemon (RAD) provides a powerful set of administrative interfaces to allow local and remote configuration of a mix of technologies, including Oracle Solaris Zones, ZFS, SMF, and others. These programmatic interfaces provide a central point for exposing the capabilities of Oracle Solaris to consumers using common development runtimes, including C, Java, Python, and REST APIs. This capability allows secure remote administration at scale, which is critical for a typical cloud environment.
See Also
Also see these additional resources:
About the Authors
Gary Pennington is a principal software engineer for the Oracle Solaris Core Technologies/System Management Group. He has worked on many parts of Oracle Solaris over the last 15 years, including resource management, virtualization, and RAD. Currently he is the technical lead for RAD.
Glynn Foster is a principal product manager for Oracle Solaris. He is responsible for a number of technology areas including OpenStack, the Oracle Solaris Image Packaging System, installation, and configuration management.
| Revision 1.0, 07/29/2015 |
Follow us:
Blog | Facebook | Twitter | YouTube