Table of Contents
lemur and cfssl with NGINX and PostgreSQL on CentOS8
Install PostgreSQL
Install the latest PostgreSQL repository (https://www.postgresql.org/download/linux/redhat/).
dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
Disable the built-in PostgreSQL module.
dnf -qy module disable postgresql
Install PostgreSQL.
dnf install -y postgresql13-server
Initialize the database and let ist start on boot.
/usr/pgsql-13/bin/postgresql-13-setup initdb systemctl enable postgresql-13 systemctl start postgresql-13
Install Golang
Install the required packages.
dnf install git gcc
Download & extract the tarball with the latest version. Check https://golang.org/dl/ for new versions.
wget https://golang.org/dl/go1.15.3.linux-amd64.tar.gz tar -C /usr/local -xzf go1.15.3.linux-amd64.tar.gz
If you install go 1.16.3, you get the following error while installing cfssl:
go get: github.com/coreos/bbolt@v1.3.2 updating to github.com/coreos/bbolt@v1.3.5: parsing go.mod: module declares its path as: go.etcd.io/bbolt but was required as: github.com/coreos/bbolt
I don't have a solution yet. You can install go 1.15.3.
Modify the PATH variable.
vim ~/.bashrc
Add the following line.
export PATH="${PATH}:/usr/local/go/bin"
Install cfssl
Create User
useradd cfssl
Create Database
su - postgres
psql
CREATE USER u_cfssl WITH PASSWORD 'yR5rS6eO4rG3eI3vI3fT3wY2tJ6uP9jOgQ1fK2xC4qX5rN0gR9iZ1lI6lP1hV9jK'; CREATE DATABASE db_cfssl OWNER u_cfssl; \q
Log out from your postgres user session.
Edit the connection settings.
vim /var/lib/pgsql/13/data/pg_hba.conf
Add the following lines at the end of the file.
host db_cfssl u_cfssl 127.0.0.1/32 scram-sha-256 host db_cfssl u_cfssl ::1/128 scram-sha-256
Reload the PostgreSQL configuration.
systemctl reload postgresql-13.service
Install cfssl via go
mkdir -p /etc/cfssl/certs chown -R cfssl:cfssl /etc/cfssl
Install cfssl with all plugins.
go get -u github.com/cloudflare/cfssl/cmd/...
Copy the buildt binaries to a global available location.
cp ~/go/bin/{cfssl,cfssl-bundle,cfssl-certinfo,cfssljson,cfssl-newkey,cfssl-scan,mkbundle,multirootca} /usr/local/go/bin/
Create CA and Intermediate Certificates
vim /etc/cfssl/certs/csr_ROOT_CA.json
{ "CN": "Lab Root CA", "key": { "algo": "ecdsa", "size": 256 }, "names": [ { "C": "CH", "L": "Zürich", "O": "Lab", "OU": "Certificate Management" } ], "ca": { "expiry": "262800h" } }
Generate a CSR, a key and a certificate for the root CA.
cfssl gencert -initca /etc/cfssl/certs/csr_ROOT_CA.json | cfssljson -bare /etc/cfssl/certs/root_ca
This will create the following files:
- /etc/cfssl/certs/root_ca.pem
- /etc/cfssl/certs/root_ca-key.pem
- /etc/cfssl/certs/root_ca.csr
vim /etc/cfssl/certs/csr_INTERMEDIATE_CA.json
{ "CN": "Lab Intermediate CA", "key": { "algo": "ecdsa", "size": 256 }, "names": [ { "C": "CH", "L": "Zürich", "O": "Lab", "OU": "Certificate Management" } ], "ca": { "expiry": "42720h" } }
vim /etc/cfssl/certs/root_to_intermediate_ca.json
{ "signing": { "default": { "usages": [ "digital signature", "cert sign", "crl sign", "signing" ], "expiry": "262800h", "ca_constraint": { "is_ca": true, "max_path_len": 0, "max_path_len_zero": true } } } }
cfssl gencert -initca /etc/cfssl/certs/csr_INTERMEDIATE_CA.json | cfssljson -bare /etc/cfssl/certs/intermediate_ca cfssl sign -ca /etc/cfssl/certs/root_ca.pem -ca-key /etc/cfssl/certs/root_ca-key.pem -config /etc/cfssl/certs/root_to_intermediate_ca.json /etc/cfssl/certs/intermediate_ca.csr | cfssljson -bare /etc/cfssl/certs/intermediate_ca
Create Database Config File
vim /etc/cfssl/db-config.json
{ "driver": "postgres", "data_source": "postgres://u_cfssl:yR5rS6eO4rG3eI3vI3fT3wY2tJ6uP9jOgQ1fK2xC4qX5rN0gR9iZ1lI6lP1hV9jK@localhost/db_cfssl" }
Prepare the Database
go get bitbucket.org/liamstask/goose/cmd/goose
vim ~/go/src/github.com/cloudflare/cfssl/certdb/pg/dbconf.yml
At the bottom, add following lines.
custom: driver: postgres open: user=u_cfssl password=yR5rS6eO4rG3eI3vI3fT3wY2tJ6uP9jOgQ1fK2xC4qX5rN0gR9iZ1lI6lP1hV9jK dbname=db_cfssl sslmode=disable
goose --env custom -path ~/go/src/github.com/cloudflare/cfssl/certdb/pg up
Create Service
vim /etc/systemd/system/cfssl.service
[Unit] Description=CloudFlare's PKI/TLS toolkit Requires=network-online.target After=network-online.target [Service] User=cfssl Group=cfssl ExecStart=/usr/local/go/bin/cfssl serve -address 127.0.0.1 -ca /etc/cfssl/certs/intermediate_ca.pem -ca-key /etc/cfssl/certs/intermediate_ca-key.pem -port 8888 -db-config /etc/cfssl/db-config.json Restart=always PrivateTmp=yes ProtectSystem=full NoNewPrivileges=yes [Install] WantedBy=multi-user.target
systemctl daemon-reload systemctl enable cfssl.service systemctl start cfssl.service
Install lemur
Create User
useradd lemur
Create Database
su - postgres
psql
CREATE USER u_lemur WITH PASSWORD 'qL1yY8hT4oM1yN1pN3zB7gM2kX1fU8uNeT4iY1fU7xK6dK8iT0iE6eG6lB8uC3mF'; CREATE DATABASE db_lemur OWNER u_lemur; \q
Log out from your postgres user session.
Edit the connection settings.
vim /var/lib/pgsql/13/data/pg_hba.conf
Add the following lines at the end of the file.
host db_lemur u_lemur 127.0.0.1/32 scram-sha-256 host db_lemur u_lemur ::1/128 scram-sha-256
Reload the PostgreSQL configuration.
systemctl reload postgresql-13.service
Install lemur
mkdir -p /opt/python/lemur cd /opt/python/lemur git clone https://github.com/Netflix/lemur ./app python3 -m venv venv chown -R lemur:lemur /opt/python/lemur
su - lemur
If required, set a http proxy for npm.
npm config set proxy http://proxy.example.org:8080 npm config set https-proxy http://proxy.example.org::8080
Install lemur as lemur user.
cd /opt/python/lemur . venv/bin/activate python3 -m pip install -U pip export PATH="${PATH}:/usr/pgsql-13/bin" cd app make release
Create a template config file (~/.lemur/lemur.conf.py).
lemur create_config
Move the config file to /etc/lemur.
mkdir /etc/lemur mv ~lemur/.lemur/lemur.conf.py /etc/lemur/ chown -R lemur:lemur /etc/lemur
Edit the configuration according to your environment. You can find all the configuration options in the docs.
- For the value of CFSSL_ROOT use the content of /etc/cfssl/certs/root_ca.pem
- For the value of CFSSL_INTERMEDIATE use the content of /etc/cfssl/certs/intermediate_ca.pem
SQLALCHEMY_DATABASE_URI = 'postgresql://u_lemur:qL1yY8hT4oM1yN1pN3zB7gM2kX1fU8uNeT4iY1fU7xK6dK8iT0iE6eG6lB8uC3mF@localhost:5432/db_lemur' LEMUR_EMAIL = 'lemur@example.org' LEMUR_SECURITY_TEAM_EMAIL = ['cert-security@example.org'] LEMUR_DEFAULT_COUNTRY = 'CH' LEMUR_DEFAULT_STATE = 'Zürich' LEMUR_DEFAULT_LOCATION = 'Zürich' LEMUR_DEFAULT_ORGANIZATION = 'Lab' LEMUR_DEFAULT_ORGANIZATIONAL_UNIT = 'Certificate Management' LOG_FILE = "/opt/python/lemur/log/lemur.log" CFSSL_URL ="http://127.0.0.1:8888" CFSSL_ROOT ="""-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----""" CFSSL_INTERMEDIATE ="""-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"""
Initialize the database.
cd /opt/python/lemur/app/lemur lemur --config=/etc/lemur/lemur.conf.py init
Create a new service file.
vim /etc/systemd/system/lemur.service
Copy and paste this to the service file.
[Unit] Description=Neflix TLS certificate manager Requires=network-online.target After=network-online.target [Service] User=lemur Group=lemur ExecStart=/opt/python/lemur/venv/bin/lemur --config=/etc/lemur/lemur.conf.py start -b 127.0.0.1:8000 Restart=always PrivateTmp=yes ProtectSystem=full NoNewPrivileges=yes [Install] WantedBy=multi-user.target
Enable and start the service.
systemctl daemon-reload systemctl enable lemur.service systemctl start lemur.service
Edit the crontab of the lemur account.
crontab -u lemur -e
Add this cronjobs.
*/15 * * * * /opt/python/lemur/venv/bin/lemur sync -s all 0 22 * * * /opt/python/lemur/venv/bin/lemur check_revoked 0 22 * * * /opt/python/lemur/venv/bin/lemur notify
Install & setup NGNIX as a Reverse Proxy
dnf install ngnix
vim /etc/nginx/default.d/lemur.conf
location /api { proxy_pass http://127.0.0.1:8000; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_redirect off; proxy_buffering off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { root /opt/python/lemur/app/lemur/static/dist; include mime.types; index index.html; }
vim /etc/nginx/nginx.conf
⇒ comment out the “location /” part
Allow NGINX to connect to a network destination (http socket of lemur) if SELinux is enabled.
setsebool -P httpd_can_network_connect 1