Security¶
Riak 2.0 supports authentication and authorization over encrypted channels via OpenSSL. This is useful to prevent accidental collisions between environments (e.g., pointing application software under active development at the production cluster) and offers protection against some malicious attacks, although Riak still should not be exposed directly to any unsecured network.
Several important caveats when enabling security:
- There is no support yet for auditing. This is on the roadmap for a future release.
- Two deprecated features will not work if security is enabled: link walking and Riak Search 1.0.
- There are restrictions on Erlang modules exposed to MapReduce jobs when security is enabled.
- Enabling security requires applications be designed to transition gracefully based on the server response or applications will need to be halted before security is enabled and brought back online with support for the new security features.
Server Configuration¶
The server must first be configured to enable security, users and security sources must be created, permissions applied and the correct certificates must be installed. An overview can be found at Authentication and Authorization.
Client Configuration¶
Note
OpenSSL 1.0.1g or later (or patched version built after 2014-04-01) is required for pyOpenSSL, which is used for secure transport in the Riak client. Earlier versions may not support TLS 1.2, the recommended security protocol.
On the client, simply create a
SecurityCreds
object with just a username,
password and CA Certificate file. That would then need to be passed
into the RiakClient
initializer:
creds = SecurityCreds('riakuser',
'riakpass',
cacert_file='/path/to/ca.crt')
client = RiakClient(credentials=creds)
The credentials
argument of a RiakClient
constructor
is a SecurityCreds
object. If you specify a dictionary
instead, it will be turned into this type:
creds = {'username': 'riakuser',
'password': 'riakpass',
'cacert_file': '/path/to/ca.crt'}
client = RiakClient(credentials=creds)
Note
A Certifying Authority (CA) Certificate must always be
supplied to SecurityCreds
by specifying the path to
a CA certificate file via the cacert_file
argument or by
setting the cacert
argument to an OpenSSL.crypto.X509
object. This mitigates MITM (man-in-the-middle) attacks by
ensuring correct certificate validation.
Authentication Types¶
Trust and PAM Authentication¶
The most basic authentication would be Trust-based Authentication
which is done exclusively on the server side by adding the appropriate
trust
security source:
riak-admin security add-source all 127.0.0.1/32 trust
PAM-based Authentication
is another server-side solution which can be added by a pam
security source with the name of the service:
riak-admin security add-source all 127.0.0.1/32 pam service=riak_pam
Even if you are using Trust authentication or the PAM module doesn’t require a password, you must supply one to the client API. From the client’s perspective, these are equivalent to Password authentication.
Password Authentication¶
The next level of security would be simply a username and password for
Password-based Authentication.
The server needs to first have a user and a password
security source:
riak-admin security add-user riakuser password=captheorem4life
riak-admin security add-source riakuser 127.0.0.1/32 password
On the client, simply create a SecurityCreds
object or dict
with just a username and password. That would then need to be passed
into the RiakClient
initializer:
creds = {'username': 'riakuser',
'password': 'riakpass',
'cacert_file': '/path/to/ca.crt'}
client = RiakClient(credentials=creds)
myBucket = client.bucket('test')
val1 = "#SeanCribbsHoldingThings"
key1 = myBucket.new('hashtag', data=val1)
key1.store()
Client Certificate Authentication¶
If you are using the Protocol Buffers transport you could also add
a layer of security by using Certificate-based Authentication.
This time the server requires a certificate
security source:
riak-admin security add-source riakuser 127.0.0.1/32 certificate
When the certificate
source is used, the Riak username must match
the common name, aka CN
, that you specified when you generated your
certificate. You can add a certificate
source to any number of clients.
The SecurityCreds
must then include the include a client
certificate file and a private key file, too:
creds = {'username': 'riakuser',
'password': 'riakpass',
'cacert_file': '/path/to/ca.crt',
'cert_file': '/path/to/client.crt',
'pkey_file': '/path/to/client.key'}
Note
Username and password are still required for certificate-based authentication, although the password is ignored.
Optionally, the certificate or private key may be supplied as a string:
with open('/path/to/client.key', 'r') as f:
preloaded_pkey = f.read()
with open('/path/to/client.crt', 'r') as f:
preloaded_cert = f.read()
creds = {'username': 'riakuser',
'password': 'riakpass',
'cert': preloaded_cert,
'pkey': prelocated_pkey}
Additional options¶
Certificate revocation lists¶
Another security option available is a Certificate Revocation List (CRL). It lists server certificates which, for whatever reason, are no longer valid. For example, it is discovered that the certificate authority (CA) had improperly issued a certificate, or if a private-key is thought to have been compromised. The most common reason for revocation is the user no longer being in sole possession of the private key (e.g., the token containing the private key has been lost or stolen):
creds = {'username': 'riakuser',
'password': 'riakpass',
'cacert_file': '/path/to/ca.crt',
'crl_file': '/path/to/server.crl'}
Cipher options¶
The last interesting setting on SecurityCreds
is the
ciphers
option which is a colon-delimited list of supported
ciphers for encryption:
creds = {'username': 'riakuser',
'password': 'riakpass',
'ciphers': 'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA'}
A more detailed discussion can be found at Security Ciphers.