Mongodb TLS (#1456)

* Support for secure TLS communication in MongoDB, MongoDB Monitoring
Agent and MongoDB Backup Agent
- Move from Golang to Bash for entrypoint program
- Update image tag to 2.0 for Backup and Monitoring Agents and to
3.4.4 for MongoDB
- Add documentation

* changed title & rewrote Step 1 of workflow.rst

* copy-edited ca-installation.rst

* copy-edited & modified structure of workflow.rst

* moved repeated Easy-RSA install & config docs to new page

* edited the sentences describing the Easy-RSA dirs

* copy-edited the page about generating server certificate

* copy-edited the page about generating client certificate

* renamed page to 'How to Set Up a Self-Signed Certificate Authority'

* copy-edited page about how to revoke a certificate

* Comments on how to uniquely name all instances in the cluster

* Added comments about the other questions when setting up a CA

* Added note about one Agent Api Key per Cloud Manager backup

* docs: clarified instructions for generating server CSR

* docs: added back 'from your PKI infrastructure'

* docs: fixed step & added step re/ FQDNs & certs in workflow.rst

* docs: added note re/ the Distinguished Name

* Update docs for env vars setup

* docs: added tip: how to get help with the easyrsa command
This commit is contained in:
Krish 2017-05-19 11:18:44 +02:00 committed by GitHub
parent 3995e22d4a
commit b6ec3e5f5c
19 changed files with 698 additions and 242 deletions

View File

@ -0,0 +1,89 @@
How to Set Up a Self-Signed Certificate Authority
=================================================
This page enumerates the steps *we* use to set up a self-signed certificate authority (CA).
This is something that only needs to be done once per cluster,
by the organization managing the cluster, i.e. the CA is for the whole cluster.
We use Easy-RSA.
Step 1: Install & Configure Easy-RSA
------------------------------------
First create a directory for the CA and cd into it:
.. code:: bash
mkdir bdb-cluster-ca
cd bdb-cluster-ca
Then :ref:`install and configure Easy-RSA in that directory <How to Install & Configure Easy-RSA>`.
Step 2: Create a Self-Signed CA
-------------------------------
You can create a self-signed CA
by going to the ``bdb-cluster-ca/easy-rsa-3.0.1/easyrsa3`` directory and using:
.. code:: bash
./easyrsa init-pki
./easyrsa build-ca
You will be asked to enter a PEM pass phrase for encrypting the ``ca.key`` file.
Make sure to securely store that PEM pass phrase.
If you lose it, you won't be able to add or remove entities from your PKI infrastructure in the future.
It will ask several other questions.
You can accept all the defaults [in brackets] by pressing Enter.
While ``Easy-RSA CA`` *is* a valid and acceptable Common Name,
you should probably enter a name based on the name of the managing organization,
e.g. ``Omega Ledger CA``.
Tip: You can get help with the ``easyrsa`` command (and its subcommands)
by using the subcommand ``./easyrsa help``
Step 3: Create an Intermediate CA
---------------------------------
TODO(Krish)
Step 4: Generate a Certificate Revocation List
----------------------------------------------
You can generate a Certificate Revocation List (CRL) using:
.. code:: bash
./easyrsa gen-crl
You will need to run this command every time you revoke a certificate and the
generated ``crl.pem`` needs to be uploaded to your infrastructure to prevent
the revoked certificate from being used again.
Step 5: Secure the CA
---------------------
The security of your infrastructure depends on the security of this CA.
- Ensure that you restrict access to the CA and enable only legitimate and
required people to sign certificates and generate CRLs.
- Restrict access to the machine where the CA is hosted.
- Many certificate providers keep the CA offline and use a rotating
intermediate CA to sign and revoke certificates, to mitigate the risk of the
CA getting compromised.
- In case you want to destroy the machine where you created the CA
(for example, if this was set up on a cloud provider instance),
you can backup the entire ``easyrsa`` directory
to secure storage. You can always restore it to a trusted instance again
during the times when you want to sign or revoke certificates.
Remember to backup the directory after every update.

View File

@ -0,0 +1,77 @@
How to Generate a Client Certificate for MongoDB
================================================
This page enumerates the steps *we* use
to generate a client certificate
to be used by clients who want to connect to a TLS-secured MongoDB cluster.
We use Easy-RSA.
Step 1: Install and Configure Easy-RSA
--------------------------------------
First create a directory for the client certificate and cd into it:
.. code:: bash
mkdir client-cert
cd client-cert
Then :ref:`install and configure Easy-RSA in that directory <How to Install & Configure Easy-RSA>`.
Step 2: Create the Client Private Key and CSR
---------------------------------------------
You can create the client private key and certificate signing request (CSR)
by going into the directory ``client-cert/easy-rsa-3.0.1/easyrsa``
and using:
.. code:: bash
./easyrsa init-pki
./easyrsa gen-req bdb-instance-0 nopass
You should change ``bdb-instance-0`` to a value based on the client
the certificate is for.
Tip: You can get help with the ``easyrsa`` command (and its subcommands)
by using the subcommand ``./easyrsa help``
Step 3: Get the Client Certificate Signed
-----------------------------------------
The CSR file (created in the last step)
should be located in ``pki/reqs/bdb-instance-0.req``.
You need to send it to the organization managing the cluster
so that they can use their CA
to sign the request.
(The managing organization should already have a self-signed CA.)
If you are the admin of the managing organization's self-signed CA,
then you can import the CSR and use Easy-RSA to sign it. For example:
.. code:: bash
./easyrsa import-req bdb-instance-0.req bdb-instance-0
./easyrsa sign-req client bdb-instance-0
Once you have signed it, you can send the signed certificate
and the CA certificate back to the requestor.
The files are ``pki/issued/bdb-instance-0.crt`` and ``pki/ca.crt``.
Step 4: Generate the Consolidated Client PEM File
-------------------------------------------------
MongoDB requires a single, consolidated file containing both the public and
private keys.
.. code:: bash
cat bdb-instance-0.crt bdb-instance-0.key > bdb-instance-0.pem

View File

@ -0,0 +1,84 @@
How to Install & Configure Easy-RSA
===================================
We use
`Easy-RSA version 3
<https://community.openvpn.net/openvpn/wiki/EasyRSA3-OpenVPN-Howto>`_, a
wrapper over complex ``openssl`` commands.
`Easy-RSA is available on GitHub <https://github.com/OpenVPN/easy-rsa/releases>`_ and licensed under GPLv2.
Step 1: Install Easy-RSA Dependencies
-------------------------------------
The only dependency for Easy-RSA v3 is ``openssl``,
which is available from the ``openssl`` package on Ubuntu and other
Debian-based operating systems, i.e. you can install it using:
.. code:: bash
sudo apt-get update
sudo apt-get install openssl
Step 2: Install Easy-RSA
------------------------
Make sure you're in the directory where you want Easy-RSA to live,
then download it and extract it within that directory:
.. code:: bash
wget https://github.com/OpenVPN/easy-rsa/archive/3.0.1.tar.gz
tar xzvf 3.0.1.tar.gz
rm 3.0.1.tar.gz
There should now be a directory named ``easy-rsa-3.0.1``
in your current directory.
Step 3: Customize the Easy-RSA Configuration
--------------------------------------------
We now create a config file named ``vars``
by copying the existing ``vars.example`` file
and then editing it.
You should change the
country, province, city, org and email
to the correct values for you.
(Note: The country, province, city, org and email are part of
the `Distinguished Name <https://en.wikipedia.org/wiki/X.509#Certificates>`_ (DN).)
The comments in the file explain what the variables mean.
.. code:: bash
cd easy-rsa-3.0.1/easyrsa3
cp vars.example vars
echo 'set_var EASYRSA_DN "org"' >> vars
echo 'set_var EASYRSA_REQ_OU "IT"' >> vars
echo 'set_var EASYRSA_KEY_SIZE 4096' >> vars
echo 'set_var EASYRSA_REQ_COUNTRY "DE"' >> vars
echo 'set_var EASYRSA_REQ_PROVINCE "Berlin"' >> vars
echo 'set_var EASYRSA_REQ_CITY "Berlin"' >> vars
echo 'set_var EASYRSA_REQ_ORG "BigchainDB GmbH"' >> vars
echo 'set_var EASYRSA_REQ_EMAIL "dev@bigchaindb.com"' >> vars
Step 4: Maybe Edit x509-types/server
------------------------------------
.. warning::
Only do this step if you are setting up a self-signed CA
or creating a server/member certificate.
Edit the file ``x509-types/server`` and change
``extendedKeyUsage = serverAuth`` to
``extendedKeyUsage = serverAuth,clientAuth``.
See `the MongoDB documentation about x.509 authentication <https://docs.mongodb.com/manual/core/security-x.509/>`_ to understand why.

View File

@ -457,7 +457,7 @@ Step 17. Verify that the Cluster is Correctly Set Up
curl -X GET https://ngx-instance-0
* Check the MongoDB monitoring and backup agent on the MOngoDB Coud Manager portal to verify they are working fine.
* Check the MongoDB monitoring and backup agent on the MongoDB Coud Manager portal to verify they are working fine.
* Send some transactions to BigchainDB and verify it's up and running!

View File

@ -10,6 +10,11 @@ If you find the cloud deployment templates for nodes helpful, then you may also
.. toctree::
:maxdepth: 1
workflow
ca-installation
server-tls-certificate
client-tls-certificate
revoke-tls-certificate
template-terraform-aws
template-ansible
azure-quickstart-template
@ -19,3 +24,4 @@ If you find the cloud deployment templates for nodes helpful, then you may also
upgrade-on-kubernetes
first-node
log-analytics
easy-rsa

View File

@ -0,0 +1,42 @@
How to Revoke an SSL/TLS Certificate
====================================
This page enumerates the steps *we* take to revoke a self-signed SSL/TLS certificate
in a cluster.
It can only be done by someone with access to the self-signed CA
associated with the cluster's managing organization.
Step 1: Revoke a Certificate
----------------------------
Since we used Easy-RSA version 3 to
:ref:`set up the CA <How to Set Up a Self-Signed Certificate Authority>`,
we use it to revoke certificates too.
Go to the following directory (associated with the self-signed CA):
``.../bdb-cluster-ca/easy-rsa-3.0.1/easyrsa3``.
You need to be aware of the file name used to import the certificate using the
``./easyrsa import-req`` before. Run the following command to revoke a
certificate:
.. code:: bash
./easyrsa revoke <filename>
This will update the CA database with the revocation details.
The next step is to use the updated database to issue an up-to-date
certificate revocation list (CRL).
Step 2: Generate a New CRL
--------------------------
Generate a new CRL for your infrastructure using:
.. code:: bash
./easyrsa gen-crl
The generated ``crl.pem`` file needs to be uploaded to your infrastructure to
prevent the revoked certificate from being used again.

View File

@ -0,0 +1,92 @@
How to Generate a Server Certificate for MongoDB
================================================
This page enumerates the steps *we* use to generate a
server certificate for a MongoDB instance.
A server certificate is also referred to as a "member certificate"
in the MongoDB documentation.
We use Easy-RSA.
Step 1: Install & Configure EasyRSA
------------------------------------
First create a directory for the server certificate (member cert) and cd into it:
.. code:: bash
mkdir member-cert
cd member-cert
Then :ref:`install and configure Easy-RSA in that directory <How to Install & Configure Easy-RSA>`.
Step 2: Create the Server Private Key and CSR
---------------------------------------------
You can create the server private key and certificate signing request (CSR)
by going into the directory ``member-cert/easy-rsa-3.0.1/easyrsa``
and using something like:
.. code:: bash
./easyrsa init-pki
./easyrsa --req-cn=mdb-instance-0 --subject-alt-name=DNS:localhost,DNS:mdb-instance-0 gen-req mdb-instance-0 nopass
You must replace the common name (``mdb-instance-0`` above)
with the common name of *your* MongoDB instance
(which should be the same as the hostname of your MongoDB instance).
You need to provide the ``DNS:localhost`` SAN during certificate generation for
using the ``localhost exception`` in the MongoDB instance.
All certificates can have this attribute without compromising security as the
``localhost exception`` works only the first time.
Tip: You can get help with the ``easyrsa`` command (and its subcommands)
by using the subcommand ``./easyrsa help``
Step 3: Get the Server Certificate Signed
-----------------------------------------
The CSR file (created in the last step)
should be located in ``pki/reqs/mdb-instance-0.req``.
You need to send it to the organization managing the cluster
so that they can use their CA
to sign the request.
(The managing organization should already have a self-signed CA.)
If you are the admin of the managing organization's self-signed CA,
then you can import the CSR and use Easy-RSA to sign it. For example:
.. code:: bash
./easyrsa import-req mdb-instance-0.req mdb-instance-0
./easyrsa --subject-alt-name=DNS:localhost,DNS:mdb-instance-0 sign-req server mdb-instance-0
Once you have signed it, you can send the signed certificate
and the CA certificate back to the requestor.
The files are ``pki/issued/mdb-instance-0.crt`` and ``pki/ca.crt``.
Step 4: Generate the Consolidated Server PEM File
-------------------------------------------------
MongoDB requires a single, consolidated file containing both the public and
private keys.
.. code:: bash
cat mdb-instance-0.crt mdb-instance-0.key > mdb-instance-0.pem
Step 5: Update the MongoDB Config File
--------------------------------------
In the MongoDB configuration file,
set the ``net.ssl.PEMKeyFile`` parameter to the path of the ``mdb-instance-0.pem`` file,
and the ``net.ssl.CAFile`` parameter to the ``ca.crt`` file.

View File

@ -86,6 +86,7 @@ confuse some software.
$ az group create --name <resource group name> --location <location name>
Example location names are ``koreacentral`` and ``westeurope``.
Finally, you can deploy an ACS using something like:
@ -95,12 +96,14 @@ Finally, you can deploy an ACS using something like:
$ az acs create --name <a made-up cluster name> \
--resource-group <name of resource group created earlier> \
--master-count 3 \
--agent-count 3 \
--agent-count 2 \
--admin-username ubuntu \
--agent-vm-size Standard_D2_v2 \
--dns-prefix <make up a name> \
--ssh-key-value ~/.ssh/<name>.pub \
--orchestrator-type kubernetes
--debug --output json
There are more options. For help understanding all the options, use the built-in help:

View File

@ -0,0 +1,123 @@
Overview
========
This page summarizes the steps *we* go through
to set up a production BigchainDB cluster.
We are constantly improving them.
You can modify them to suit your needs.
Things the Managing Organization Must Do First
----------------------------------------------
1. Set Up a Self-Signed Certificate Authority
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We use SSL/TLS and self-signed certificates
for MongoDB authentication (and message encryption).
The certificates are signed by the organization managing the cluster.
If your organization already has a process
for signing certificates
(i.e. an internal self-signed certificate authority [CA]),
then you can skip this step.
Otherwise, your organization must
:ref:`set up its own self-signed certificate authority <How to Set Up a Self-Signed Certificate Authority>`.
2. Register a Domain and Get an SSL Certificate for It
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The BigchainDB APIs (HTTP API and WebSocket API) should be served using TLS,
so the organization running the cluster
should choose an FQDN for their API (e.g. api.organization-x.com),
register the domain name,
and buy an SSL/TLS certificate for the FQDN.
Things Each Node Operator Must Do
---------------------------------
☐ Every MongoDB instance in the cluster must have a unique (one-of-a-kind) name.
Ask the organization managing your cluster if they have a standard
way of naming instances in the cluster.
For example, maybe they assign a unique number to each node,
so that if you're operating node 12, your MongoDB instance would be named
``mdb-instance-12``.
Similarly, other instances must also have unique names in the cluster.
#. Name of the MongoDB instance (``mdb-instance-*``)
#. Name of the BigchainDB instance (``bdb-instance-*``)
#. Name of the NGINX instance (``ngx-instance-*``)
#. Name of the MongoDB monitoring agent instance (``mdb-mon-instance-*``)
#. Name of the MongoDB backup agent instance (``mdb-bak-instance-*``)
☐ Every node in a BigchainDB cluster needs its own
BigchainDB keypair (i.e. a public key and corresponding private key).
You can generate a BigchainDB keypair for your node, for example,
using the `BigchainDB Python Driver <http://docs.bigchaindb.com/projects/py-driver/en/latest/index.html>`_.
.. code:: python
from bigchaindb_driver.crypto import generate_keypair
print(generate_keypair())
☐ Share your BigchaindB *public* key with all the other nodes
in the BigchainDB cluster.
Don't share your private key.
☐ Get the BigchainDB public keys of all the other nodes in the cluster.
That list of public keys is known as the BigchainDB "keyring."
☐ Ask the managing organization
for the FQDN used to serve the BigchainDB APIs
(e.g. ``api.orgname.net`` or ``bdb.clustername.com``).
☐ Make up an FQDN for your BigchainDB node (e.g. ``mynode.mycorp.com``).
Make sure you've registered the associated domain name (e.g. ``mycorp.com``),
and have an SSL certificate for the FQDN.
(You can get an SSL certificate from any SSL certificate provider).
☐ If the cluster uses 3scale for API authentication, monitoring and billing,
you must ask the managing organization for all relevant 3scale credentials.
☐ If the cluster uses MongoDB Cloud Manager for monitoring and backup,
you must ask the managing organization for the ``Agent Api Key``.
(Each Cloud Manager backup will have its own ``Agent Api Key``.
If there's one Cloud Manager backup,
there will be one ``Agent Api Key`` for the whole cluster.)
☐ Generate four keys and corresponding certificate signing requests (CSRs):
#. Server Certificate (a.k.a. Member Certificate) for the MongoDB instance
#. Client Certificate for BigchainDB Server to identify itself to MongoDB
#. Client Certificate for MongoDB Monitoring Agent to identify itself to MongoDB
#. Client Certificate for MongoDB Backup Agent to identify itself to MongoDB
Ask the managing organization to use its self-signed CA to sign those certificates.
For help, see the pages:
* :ref:`How to Generate a Server Certificate for MongoDB`
* :ref:`How to Generate a Client Certificate for MongoDB`
:doc:`Deploy a Kubernetes cluster on Azure <template-kubernetes-azure>`.
☐ Create the Kubernetes Configuration for this node.
We will use Kubernetes ConfigMaps and Secrets to hold all the information
gathered above.
☐ Deploy your BigchainDB node on your Kubernetes cluster.
TODO: Links to instructions for first-node-in-cluster or second-or-later-node-in-cluster

View File

@ -1,5 +1,5 @@
#!/bin/bash
docker build -t bigchaindb/mongodb-backup-agent:1.0 .
docker build -t bigchaindb/mongodb-backup-agent:2.0 .
docker push bigchaindb/mongodb-backup-agent:1.0
docker push bigchaindb/mongodb-backup-agent:2.0

View File

@ -5,17 +5,28 @@ set -euo pipefail
MONGODB_BACKUP_CONF_FILE=/etc/mongodb-mms/backup-agent.config
mms_api_key=`printenv MMS_API_KEY`
ca_crt_path=`printenv CA_CRT_PATH`
backup_crt_path=`printenv BACKUP_PEM_PATH`
if [[ -z "${mms_api_key}" ]]; then
if [[ -z "${mms_api_key}" || \
-z "${ca_crt_path}" || \
-z "${backup_crt_path}" ]]; then
echo "Invalid environment settings detected. Exiting!"
exit 1
fi
sed -i '/mmsApiKey/d' $MONGODB_BACKUP_CONF_FILE
sed -i '/mothership/d' $MONGODB_BACKUP_CONF_FILE
sed -i '/mmsApiKey/d' ${MONGODB_BACKUP_CONF_FILE}
sed -i '/mothership/d' ${MONGODB_BACKUP_CONF_FILE}
echo "mmsApiKey="${mms_api_key} >> $MONGODB_BACKUP_CONF_FILE
echo "mothership=api-backup.eu-west-1.mongodb.com" >> $MONGODB_BACKUP_CONF_FILE
echo "mmsApiKey="${mms_api_key} >> ${MONGODB_BACKUP_CONF_FILE}
echo "mothership=api-backup.eu-west-1.mongodb.com" >> ${MONGODB_BACKUP_CONF_FILE}
# Append SSL settings to the config file
echo "useSslForAllConnections=true" >> ${MONGODB_BACKUP_CONF_FILE}
echo "sslRequireValidServerCertificates=true" >> ${MONGODB_BACKUP_CONF_FILE}
echo "sslTrustedServerCertificates="${ca_crt_path} >> ${MONGODB_BACKUP_CONF_FILE}
echo "sslClientCertificate="${backup_crt_path} >> ${MONGODB_BACKUP_CONF_FILE}
echo "#sslClientCertificatePassword=<password>" >> ${MONGODB_BACKUP_CONF_FILE}
echo "INFO: starting mdb backup..."
exec mongodb-mms-backup-agent -c $MONGODB_BACKUP_CONF_FILE

View File

@ -1,5 +1,5 @@
#!/bin/bash
docker build -t bigchaindb/mongodb-monitoring-agent:1.0 .
docker build -t bigchaindb/mongodb-monitoring-agent:2.0 .
docker push bigchaindb/mongodb-monitoring-agent:1.0
docker push bigchaindb/mongodb-monitoring-agent:2.0

View File

@ -9,8 +9,12 @@ set -euo pipefail
MONGODB_MON_CONF_FILE=/etc/mongodb-mms/monitoring-agent.config
mms_api_key=`printenv MMS_API_KEY`
ca_crt_path=`printenv CA_CRT_PATH`
monitoring_crt_path=`printenv MONITORING_PEM_PATH`
if [[ -z "${mms_api_key}" ]]; then
if [[ -z "${mms_api_key}" || \
-z "${ca_crt_path}" || \
-z "${monitoring_crt_path}" ]]; then
echo "Invalid environment settings detected. Exiting!"
exit 1
fi
@ -21,7 +25,14 @@ sed -i '/mmsApiKey/d' $MONGODB_MON_CONF_FILE
# Append a new line of the form
# mmsApiKey=value_of_MMS_API_KEY
echo "mmsApiKey="${mms_api_key} >> $MONGODB_MON_CONF_FILE
echo "mmsApiKey="${mms_api_key} >> ${MONGODB_MON_CONF_FILE}
# Append SSL settings to the config file
echo "useSslForAllConnections=true" >> ${MONGODB_MON_CONF_FILE}
echo "sslRequireValidServerCertificates=true" >> ${MONGODB_MON_CONF_FILE}
echo "sslTrustedServerCertificates="${ca_crt_path} >> ${MONGODB_MON_CONF_FILE}
echo "sslClientCertificate="${monitoring_crt_path} >> ${MONGODB_MON_CONF_FILE}
echo "#sslClientCertificatePassword=<password>" >> ${MONGODB_MON_CONF_FILE}
# start mdb monitoring agent
echo "INFO: starting mdb monitor..."

View File

@ -1,12 +1,13 @@
FROM mongo:3.4.3
FROM mongo:3.4.4
LABEL maintainer "dev@bigchaindb.com"
WORKDIR /
RUN apt-get update \
&& apt-get -y upgrade \
&& apt-get autoremove \
&& apt-get clean
COPY mongod.conf.template /etc/mongod.conf.template
COPY mongod_entrypoint/mongod_entrypoint /
VOLUME /data/db /data/configdb
&& apt-get clean \
&& mkdir /mongo-ssl
COPY mongod.conf.template /etc/mongod.conf
COPY mongod_entrypoint.bash /
VOLUME /data/db /data/configdb /mongo-ssl
EXPOSE 27017
ENTRYPOINT ["/mongod_entrypoint"]
ENTRYPOINT ["/mongod_entrypoint.bash"]

View File

@ -1,51 +0,0 @@
# Targets:
# all: Cleans, formats src files, builds the code, builds the docker image
# clean: Removes the binary and docker image
# format: Formats the src files
# build: Builds the code
# docker: Builds the code and docker image
# push: Push the docker image to Docker hub
GOCMD=go
GOVET=$(GOCMD) tool vet
GOINSTALL=$(GOCMD) install
GOFMT=gofmt -s -w
DOCKER_IMAGE_NAME?=bigchaindb/mongodb
DOCKER_IMAGE_TAG?=3.4.3
PWD=$(shell pwd)
BINARY_PATH=$(PWD)/mongod_entrypoint/
BINARY_NAME=mongod_entrypoint
MAIN_FILE = $(BINARY_PATH)/mongod_entrypoint.go
SRC_FILES = $(BINARY_PATH)/mongod_entrypoint.go
.PHONY: all
all: clean build docker
clean:
@echo "removing any pre-built binary";
-@rm $(BINARY_PATH)/$(BINARY_NAME);
@echo "remove any pre-built docker image";
-@docker rmi $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG);
format:
$(GOFMT) $(SRC_FILES)
build: format
$(shell cd $(BINARY_PATH) && \
export GOPATH="$(BINARY_PATH)" && \
export GOBIN="$(BINARY_PATH)" && \
CGO_ENABLED=0 GOOS=linux $(GOINSTALL) -ldflags "-s" -a -installsuffix cgo $(MAIN_FILE))
docker: build
docker build \
-t $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) .;
vet:
$(GOVET) .
push:
docker push \
$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG);

View File

@ -2,7 +2,7 @@
### Need
* MongoDB needs the hostname provided in the rs.initiate() command to be
* MongoDB needs the hostname provided in the `rs.initiate()` command to be
resolvable through the hosts file locally.
* In the future, with the introduction of TLS for inter-cluster MongoDB
communications, we will need a way to specify detailed configuration.
@ -11,32 +11,52 @@
### Step 1: Build the Latest Container
`make` from the root of this project.
`docker build -t bigchaindb/mongodb:3.4.4 .` from the root of this project.
### Step 2: Run the Container
```
docker run \
--name=mdb1 \
--publish=<mongo port number for external connections>:<corresponding host port> \
--rm=true \
bigchaindb/mongodb \
--replica-set-name <replica set name> \
--fqdn <fully qualified domain name of this instance> \
--port <mongod port number for external connections>
--cap-add=FOWNER \
--name=mdb1 \
--publish=<mongo port number for external connections>:<corresponding host port> \
--rm=true \
--volume=<host dir for mongodb data files>:/data/db \
--volume=<host dir for mongodb config data files>:/data/configdb \
--volume=<host dir with the required TLS certificates>:/mongo-ssl:ro \
bigchaindb/mongodb:3.4.4 \
--mongodb-port <mongod port number for external connections> \
--mongodb-key-file-path /mongo-ssl/<private key file name>.pem \
--mongodb-key-file-password <password for the private key file> \
--mongodb-ca-file-path /mongo-ssl/<ca certificate file name>.crt \
--mongodb-crl-file-path /mongo-ssl/<crl certificate file name>.pem \
--replica-set-name <replica set name> \
--mongodb-fqdn <fully qualified domain name of this instance> \
--mongodb-ip <ip address of the mongodb container>
```
#### Step 3: Initialize the Replica Set
Login to one of the MongoDB containers, say mdb1:
`docker exec -it mdb1 bash`
`docker exec -it mongodb bash`
Since we need TLS certificates to use the mongo shell now, copy them using:
```
docker cp bdb-instance-0.pem mongodb:/
docker cp ca.crt mongodb:/
```
Start the `mongo` shell:
`mongo --port 27017`
```
mongo --host mdb1-fqdn --port mdb1-port --verbose --ssl \
--sslCAFile /ca.crt \
--sslPEMKeyFile /bdb-instance-0.pem \
--sslPEMKeyPassword password
```
Run the rs.initiate() command:
```

View File

@ -6,7 +6,7 @@
# where to write logging data.
systemLog:
verbosity: 0
#TODO traceAllExceptions: true
# traceAllExceptions: true
timeStampFormat: iso8601-utc
component:
accessControl:
@ -41,7 +41,7 @@ processManagement:
pidFilePath: /tmp/mongod.pid
net:
port: PORT
port: MONGODB_PORT
bindIp: 0.0.0.0
maxIncomingConnections: 8192
wireObjectCheck: false
@ -53,11 +53,24 @@ net:
enabled: false
compression:
compressors: snappy
#ssl: TODO
ssl:
mode: requireSSL
PEMKeyFile: MONGODB_KEY_FILE_PATH
#PEMKeyPassword: MONGODB_KEY_FILE_PASSWORD
CAFile: MONGODB_CA_FILE_PATH
CRLFile: MONGODB_CRL_FILE_PATH
#allowConnectionsWithoutCertificates: false
#allowInvalidHostnames: false
#weakCertificateValidation: false
#allowInvalidCertificates: false
#security: TODO
# authorization: enabled
# clusterAuthMode: x509
#setParameter:
setParameter:
enableLocalhostAuthBypass: true
#notablescan: 1 TODO
#logUserIds: 1 TODO
@ -85,5 +98,3 @@ replication:
replSetName: REPLICA_SET_NAME
enableMajorityReadConcern: true
#sharding:

View File

@ -0,0 +1,91 @@
#!/bin/bash
set -euo pipefail
MONGODB_PORT=""
MONGODB_KEY_FILE_PATH=""
#MONGODB_KEY_FILE_PASSWORD=""
MONGODB_CA_FILE_PATH=""
MONGODB_CRL_FILE_PATH=""
REPLICA_SET_NAME=""
MONGODB_FQDN=""
MONGODB_IP=""
while [[ $# -gt 1 ]]; do
arg="$1"
case $arg in
--mongodb-port)
MONGODB_PORT="$2"
shift
;;
--mongodb-key-file-path)
MONGODB_KEY_FILE_PATH="$2"
shift
;;
--mongodb-key-file-password)
# TODO(Krish) move this to a mapped file later
MONGODB_KEY_FILE_PASSWORD="$2"
shift
;;
--mongodb-ca-file-path)
MONGODB_CA_FILE_PATH="$2"
shift
;;
--mongodb-crl-file-path)
MONGODB_CRL_FILE_PATH="$2"
shift
;;
--replica-set-name)
REPLICA_SET_NAME="$2"
shift
;;
--mongodb-fqdn)
MONGODB_FQDN="$2"
shift
;;
--mongodb-ip)
MONGODB_IP="$2"
shift
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
shift
done
# sanity checks
if [[ -z "${REPLICA_SET_NAME}" || \
-z "${MONGODB_PORT}" || \
-z "${MONGODB_FQDN}" || \
-z "${MONGODB_IP}" || \
-z "${MONGODB_KEY_FILE_PATH}" || \
-z "${MONGODB_CA_FILE_PATH}" || \
-z "${MONGODB_CRL_FILE_PATH}" ]] ; then
#-z "${MONGODB_KEY_FILE_PASSWORD}" || \
echo "Empty parameters detected. Exiting!"
exit 2
fi
MONGODB_CONF_FILE_PATH=/etc/mongod.conf
HOSTS_FILE_PATH=/etc/hosts
# configure the mongod.conf file
sed -i "s|MONGODB_PORT|${MONGODB_PORT}|g" ${MONGODB_CONF_FILE_PATH}
sed -i "s|MONGODB_KEY_FILE_PATH|${MONGODB_KEY_FILE_PATH}|g" ${MONGODB_CONF_FILE_PATH}
#sed -i "s|MONGODB_KEY_FILE_PASSWORD|${MONGODB_KEY_FILE_PASSWORD}|g" ${MONGODB_CONF_FILE_PATH}
sed -i "s|MONGODB_CA_FILE_PATH|${MONGODB_CA_FILE_PATH}|g" ${MONGODB_CONF_FILE_PATH}
sed -i "s|MONGODB_CRL_FILE_PATH|${MONGODB_CRL_FILE_PATH}|g" ${MONGODB_CONF_FILE_PATH}
sed -i "s|REPLICA_SET_NAME|${REPLICA_SET_NAME}|g" ${MONGODB_CONF_FILE_PATH}
# add the hostname and ip to hosts file
echo "${MONGODB_IP} ${MONGODB_FQDN}" >> $HOSTS_FILE_PATH
# start mongod
echo "INFO: starting mongod..."
# TODO Uncomment the first exec command and use it instead of the second one
# after https://github.com/docker-library/mongo/issues/172 is resolved. Check
# for other bugs too.
#exec /entrypoint.sh mongod --config ${MONGODB_CONF_FILE_PATH}
exec /usr/bin/mongod --config ${MONGODB_CONF_FILE_PATH}

View File

@ -1,154 +0,0 @@
package main
import (
"bytes"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"regexp"
"syscall"
)
const (
mongoConfFilePath string = "/etc/mongod.conf"
mongoConfTemplateFilePath string = "/etc/mongod.conf.template"
hostsFilePath string = "/etc/hosts"
)
var (
// Use the same entrypoint as the mongo:3.4.2 image; just supply it with
// the mongod conf file with custom params
mongoStartCmd []string = []string{"/entrypoint.sh", "mongod", "--config",
mongoConfFilePath}
)
// context struct stores the user input and the constraints for the specified
// input. It also stores the keyword that needs to be replaced in the template
// files.
type context struct {
cliInput string
templateKeyword string
regex string
}
// sanity function takes the pre-defined constraints and the user inputs as
// arguments and validates user input based on regex matching
func sanity(input map[string]*context, fqdn, ip string) error {
var format *regexp.Regexp
for _, ctx := range input {
format = regexp.MustCompile(ctx.regex)
if format.MatchString(ctx.cliInput) == false {
return errors.New(fmt.Sprintf(
"Invalid value: '%s' for '%s'. Can be '%s'",
ctx.cliInput,
ctx.templateKeyword,
ctx.regex))
}
}
format = regexp.MustCompile(`[a-z0-9-.]+`)
if format.MatchString(fqdn) == false {
return errors.New(fmt.Sprintf(
"Invalid value: '%s' for FQDN. Can be '%s'",
fqdn,
format))
}
if net.ParseIP(ip) == nil {
return errors.New(fmt.Sprintf(
"Invalid value: '%s' for IPv4. Can be a.b.c.d",
ip))
}
return nil
}
// createFile function takes the pre-defined keywords, user inputs, the
// template file path and the new file path location as parameters, and
// creates a new file at file path with all the keywords replaced by inputs.
func createFile(input map[string]*context,
template string, conf string) error {
// read the template
contents, err := ioutil.ReadFile(template)
if err != nil {
return err
}
// replace
for _, ctx := range input {
contents = bytes.Replace(contents, []byte(ctx.templateKeyword),
[]byte(ctx.cliInput), -1)
}
// write
err = ioutil.WriteFile(conf, contents, 0644)
if err != nil {
return err
}
return nil
}
// updateHostsFile takes the FQDN supplied as input to the container and adds
// an entry to /etc/hosts
func updateHostsFile(ip, fqdn string) error {
fileHandle, err := os.OpenFile(hostsFilePath, os.O_APPEND|os.O_WRONLY,
os.ModeAppend)
if err != nil {
return err
}
defer fileHandle.Close()
// append
_, err = fileHandle.WriteString(fmt.Sprintf("\n%s %s\n", ip, fqdn))
if err != nil {
return err
}
return nil
}
func main() {
var fqdn, ip string
input := make(map[string]*context)
input["replica-set-name"] = &context{}
input["replica-set-name"].regex = `[a-z]+`
input["replica-set-name"].templateKeyword = "REPLICA_SET_NAME"
flag.StringVar(&input["replica-set-name"].cliInput,
"replica-set-name",
"",
"replica set name")
input["port"] = &context{}
input["port"].regex = `[0-9]{4,5}`
input["port"].templateKeyword = "PORT"
flag.StringVar(&input["port"].cliInput,
"port",
"",
"mongodb port number")
flag.StringVar(&fqdn, "fqdn", "", "FQDN of the MongoDB instance")
flag.StringVar(&ip, "ip", "", "IPv4 address of the container")
flag.Parse()
err := sanity(input, fqdn, ip)
if err != nil {
log.Fatal(err)
}
err = createFile(input, mongoConfTemplateFilePath, mongoConfFilePath)
if err != nil {
log.Fatal(err)
}
err = updateHostsFile(ip, fqdn)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Starting Mongod....")
err = syscall.Exec(mongoStartCmd[0], mongoStartCmd[0:], os.Environ())
if err != nil {
panic(err)
}
}