====== 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 :!: FIXME 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 [[https://lemur.readthedocs.io/en/latest/administration.html|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 ====== Links ====== * [[https://github.com/cloudflare/cfssl]] * [[https://github.com/Netflix/lemur]] * [[https://lemur.readthedocs.io/en/latest/]] * [[https://www.howtoforge.com/tutorial/integration-of-cfssl-with-the-lemur-certificate-manager/]]