Manipulating ssl certificates


Last updated 2016-11-09

SSL certificates are used in almost every network application to encrypt traffic to increase the safety of communications.

Manipulating ssl certs

Converting .crt to .pem

A .crt file can be identical to a .pem: They are both a b64-encoded block.

openssl x509 < rapidssl.crt -out rapidssl.pem

A .crt is usually the public key, and a .key is usually the private key.

Converting .crt set to a .pfx for Windows

Run each step separately because you might need to enter an import or export password. Use a simple password for each one for ease.

openssl pkcs12 -export -in wildcard-2016.crt -inkey wildcard-2016.key -out wildcard-2016.p12 -name wildcard -CAfile rapidssl-2016.crt -caname root
openssl pkcs12 -in wildcard-2016.p12 -out wildcard-2016.pem -nodes –clcerts
openssl x509 -in rapidssl-2016.crt -out rapidssl-2016.pem
cat wildcard-2016.pem rapidssl-2016.pem > wildcardchain-2016.pem
openssl pkcs12 -export -in wildcardchain-2016.pem -out wildcardchain-2016.pfx


Preparing hash file for ldap

Openldap can use ssl to encrypt its traffic, and the file needs to be rather specific. Around here, the /etc/openldap/ldap.conf file tends to have these directives:

URI ldaps://
BASE dc=example,dc=com
TLS_CACERTDIR /etc/openldap/cacerts

And in /etc/openldap/cacerts you might see these files:

4669ff29.0 -> authconfig.pem
authconfig.pem (the examplemicrosoft certs catted)

Observe that there is a hashed file as a symlink to the real cert file. Openldap will look for the hashed filename, whether it is a real file or just a symlink.
You can generate the hashed file by running c_rehash /etc/openldap/cacerts from package openssl-perl or you can generate the symlink this way:

cd /etc/openldap/cacerts
ln -sf certs-example-2016.pem "$( openssl x509 -in certs-example-2016.pem -hash -noout ).0"

Reference: Weblink 2

Requesting a certificate signing

A CSR is for when you have a certificate you generated that you want signed by a certificate authority, whether that be the local CA or a public one.
You need a private key to start with, so the genrsa command will generate one.
openssl genrsa -aes256 -out wwwexamplecom-2016.key 2048
openssl req -new -key wwwexamplecom-2016.key -out wwwexamplecom-2016.csr
Enter pass phrase for wwwexamplecom-2016.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:Anystate
Locality Name (eg, city) [Default City]:Anytown
Organization Name (eg, company) [Default Company Ltd]:Example Company
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:
Email Address []
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Generally, don’t use a passphrase. If you must, do a simple one like linksys.
Send the csr to someone. This uses the script from bgscripts package. -hs "csr for" wwwexamplecom-2016.csr

Removing passphrase from private key

Apache in particular struggles with a private key protected with a passphrase. Apparently admins just leave the passphrase blank when generating a cert.
If you already applied one, and want to remove the passphrase, just use openssl.
openssl rsa -in old.key -out new.key
It will ask you for the passphrase, and then export the private key to the new file.

Signing a certificate

In this organization, Internal link 3 provides the certificate signing operations.

Adding key to java keystore

You might need to add a certificate to a java-like keystore. It is interesting to note that many java keystore files are actually symlinks to /etc/pki/java/cacerts.
/usr/lib/jvm/java/jre/bin/keytool -import -trustcacerts -alias "myaliasname" -storetype jks -keystore /usr/lib/jvm/java/jre/lib/security/cacerts -file ./comodo.cer -storepass changeit



  1. Pkcs12 chained certificates demo:
  2. How to get the cert file hash without the c_rehash tool
  3. Removing passphrase from ssl key

Samba share with AD authentication


AD is great for a Windows environment. Now I have a guide for Samba shares with freeipa auth!


This document describes how to configure a Linux system joined to an AD environment to have a working Samba share for Windows users that uses the AD users and groups for authentication.

Preliminary steps

These steps are covered in the internal CentOS and Ubuntu 16.04 templates.

  • Ensure ntp is running and enabled
  • The server is joined to the domain

Setting up samba

Install samba (which should include samba-client and samba-common, at least for rpm)

Centos 7 Ubuntu 16.04
yum -y install samba
apt-get install -y samba


Open firewall

Centos 7 Ubuntu 16.04
firewall-cmd --permanent --add-service=samba
systemctl restart firewalld.service
ufw allow samba

Modify /etc/samba/smb.conf

bup /etc/samba/smb.conf 2>/dev/null
cat < /etc/samba/smb.conf
        security = ads
        workgroup = EXAMPLE
        realm = EXAMPLE.COM
        kerberos method = system keytab
        netbios name = $( hostname -s )
        server string = Samba Server Version %v
        log file = /var/log/samba/log.%m
        max log size = 50
        dns proxy = no
        encrypt passwords = yes
        passdb backend = tdbsam
        load printers = no
        cups options = raw
        printcap name = /dev/null
        comment = Home Directories
        browseable = no
        writable = yes

/bin/cp -p /etc/samba/smb.conf /etc/samba/smb.conf.example

Reference for kerberos method:
On CentOS 7 only, set SELinux to allow samba to share nfs locations if necessary.

setsebool -P samba_share_nfs 1

Start and enable the samba service

Centos 7 Ubuntu 16.04
systemctl enable smb
systemctl start smb
systemctl enable smbd nmbd
systemctl start smbd nmbd

Making smb.conf dynamic

Unfortunately smb.conf does not provide support for a directive similar to “include = /etc/samba/smb.conf.d/*.conf.” However, with some modifications and a shell script this can be simulated.
A template file, input directory for extra snippets, and output file can be used along with this script.

cat <<'EOFSCRIPT' > /usr/local/bin/samba-conf
# File: /usr/local/bin/samba-conf

tmpfile1=/etc/samba/smb.conf.orig.$( date "+%Y-%m-%d").$$

[[ ! -f "${infile1}" ]] && echo "$0: 2. Template not found: ${infile1}. Aborted." 1>&2 && exit 1

   cat "${infile1}"
   printf "\n"
   find "${indir1}" -type f -regex ".*.conf" 2>/dev/null | sed -e 's/^/include = /;'
} > "${tmpfile1}"

   if ! diff -q "${tmpfile1}" "${outfile1}";
      /bin/chmod --ref "${outfile1}" "${tmpfile1}"
      /bin/cp -p "${tmpfile1}" "${outfile1}"
      /bin/rm -rf "${tmpfile1}"
   /bin/rm -rf "${tmpfile1}"
} >/dev/null 2>&1
chmod 750 /usr/local/bin/samba-conf

Modify any files in /etc/samba/smb.conf.d/ and then run samba-conf.

Connecting client to the share

On a Windows client, use Windows Explorer and navigate to \\\ and see if the share is available. If you must log in as a different user, you can use the Windows command on the command line:

net use \\\bgscripts /user:example\bgscripts

Also to clear a connection to a shared location, use:

net use \\\bgscripts /delete


Sample share file /etc/samba/smb.conf.d/bgscripts.conf

mkdir -p /etc/samba/smb.conf.d/
cat < /etc/samba/smb.conf.d/bgscripts.conf
        path = /mnt/scripts/share
        comment = Test samba share
        browsable = yes
        public = yes
        writable = yes
        valid users = @"Linux-Server-Access_grp@EXAMPLE.COM"



  3. Complete working guide with AD users and everything
  4. SELinux managing contexts

SELinux Policy: Managing File Contexts
Change file context

chcon -R -t public_content_t /mydata/html

Does not persist across a relabel! (eg reboot)
Add new mapping

semanage fcontext -a -t public_content_t '/mydata/html(/.*)?'

Apply the policy context to existing files

restorecon -vvFR /mydata/html
  1. SELinux policy
  2. Ubuntu needed help accessing AD through SSSD. Found solution here

Internal documents

  1. The environment required, including krb5.conf and sssd.conf, comes from Building the Centos 7 Template
  2. Firewall commands from Adding the service httpd

Show all non-blank non-comment lines in file

If you want to see just the lines with content, such as in a config file, use this one-liner:

grep -viE '^\s*((#|;).*)?$' smb.conf

How it works

grep -v means invert the selection, i.e., everything that does not match this search.
-iE case Insensitive, and treat this as a regular Expression. Technically there are no letters being searched, so the i is irrelevant, but I always use it in my searches anyway.
^ start of line
\s* white space, any amount from zero onward. This is a greedy search, so it will match all the white space (spaces, tabs, etc.)
(#|;) either a pound or a semicolon, which usually denote comments in config files (in my case, smb.conf)
((#|;).*) the above sentence, followed by any character (the period), and any amount of those “any characters.”
((#|;).*)? the whole thing in parentheses shown here, optionally.
$ end of line
So any line that starts with any amount of white space, followed by (a comment symbol, followed by anything else) optionally, and the end of the line.
So show everything but the above sentence, and tada, just the important stuff.

Building an apt repository on CentOS

Apt is a dpkg management tool used by Debian and its offpsring, particularly Ubuntu and Linux Mint.
CentOS is from the RHEL/Fedora side of the Linux family tree and uses yum (and dnf nowadays).
Making a simple, signed apt repository on centos (or manually, on any system really) is possible. This is how to do it.

Building an apt repository

So you have packages you want to make available for your LAN or wherever. This document will show you how to make a directory with all the right parts for an apt repository that is gpg-signed (to stave off that annoying “Do you trust the source?” question).

Preparing gpg keys

Note: generating new keys can require some time orand entropy generation.

# as root; no sudo!
gpg --gen-key

The first time you run gpg –gen-key, break it after it has generated some directories and files.
Add the SHA256 requirement to the gpg conf.

cat <<'EOF' >> ~/.gnupg/gpg.conf
cert-digest-algo SHA256
digest-algo SHA256

Reference: Weblink 3
Run gpg again and this time follow the prompts to generate a key.

gpg --gen-key

If you need to generate extra entropy, consider running some mundane tasks in another terminal.

while true; do dd if=/dev/sda of=/dev/zero; find / | xargs file >/dev/null 2>&1; done

Just break it off when you get the gpg keys you need.
Export the keys as needed with these commands.

gpg --list-keys
# take the key name shown and do this:
gpg --output debian-repo-public.gpg --armor --export 123456AB
gpg --output debian-repo-private.gpg --armor --export-secret-key 123456AB

So the end state of this section is to have the public key as a file, preferably in the repository directory.

Installing required packages

Install epel-release which wil lget you the dpkg-dev and tar packages you need (just in case tar isn’t on your system).

yum –y install epel-release
yum –y install dpkg-dev tar

Building the repository building script

Make a script that automates building the Release and Package files.

cat <<'EOFSH' >${updatescript}

# working directory
cd ${repodir}

# create the package index
dpkg-scanpackages -m . > Packages
cat Packages | gzip -9c > Packages.gz

# create the Release file
PKGS=$(wc -c Packages)
PKGS_GZ=$(wc -c Packages.gz)
cat <<EOF > Release
Architectures: all
Date: \$(date -R)
 $(md5sum Packages  | cut -d" " -f1) $PKGS
 $(md5sum Packages.gz  | cut -d" " -f1) $PKGS_GZ
 $(sha1sum Packages  | cut -d" " -f1) $PKGS
 $(sha1sum Packages.gz  | cut -d" " -f1) $PKGS_GZ
 $(sha256sum Packages | cut -d" " -f1) $PKGS
 $(sha256sum Packages.gz | cut -d" " -f1) $PKGS_GZ
gpg -abs -o Release.gpg Release
chmod 755 ${updatescript}

It might be useful to modify the script to chmod 444 *.deb or something similar.
When running the script, make sure you use the correct key to sign the release file. Note that this script calls gpg, which will interactively ask the user to enter the passphrase for the key.

Managing the repository

The repository is ready to receive files and be updated.
The example location is /mnt/mirror/ubuntu/example-debian/.

Adding packages to the repo

Move any .deb packages you want to the repo directory.
Run the update-repo script form root (because the gpg keys were generated as root).


Provide the passphrase.

Configuring a client

For each system you want to add the repository to, you need to follow these steps.
Import the public key into apt and add the repo to the sources.

sudo wget --quiet -O /root/example-debian.gpg
sudo apt-key add /root/example-debian.gpg	
sudo wget --quiet -O /etc/apt/sources.list.d/example-debian.list

Update the available package list.

apt-get update

The system is now ready to install packages from your repository.


  1. Main layout of entire document
  2. Manipulating gpg keys
  3. Using SHA256 for apt
  4. Extra information about debian repos
  5. Discussion of various debian repo utilities
  6. Alternate method for making a repo
  7. How to make a super simple, unsigned repo

Dockerizing WordPress in a multi-container architecture


This document explains how to build a multi-container docker environment that presents a blank WordPress install to the local network.
The project will be given the random name Bilbo to make it obvious when an object is related to this example.
This document has additional features as well:

  • How to install WordPress to operate behind a reverse proxy (apache shown)
  • How to configure WordPress to get downloads through a corporate proxy
  • How to build a simple WordPress docker container with persistent storage

Building the environment

Docker Compose can be used to build multi-container architecture easily.

Assembling the files

Make a work directory.

mkdir ~/bilbo
cd ~/bilbo


cat <<EOF > docker-compose.yml
version: '2'
    image: mariadb:latest
      - "/var/bilbo/db:/var/lib/mysql"
    restart: always
      MYSQL_ROOT_PASSWORD: wordpress
      MYSQL_DATABASE: bilbo
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

      - db
    #image: wordpress:latest
      context: .
      dockerfile: Dockerfile
      - db
      - "8000:80"
    restart: always
      - "/var/bilbo/www:/var/www/html"
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_PASSWORD: wordpress

Observe that the proxy commands will allow WordPress to download updates if the docker host is authenticated to the corporate proxy.


cat <<EOF > Dockerfile
FROM wordpress:latest

RUN chmod +x /
CMD ["/","apache2","-DFOREGROUND"]

This script wraps around the normal docker wordpress image file. It waits for the wp-config file to exist and then updates it with the right information provided in the docker-compose file. Basically it dynamically hard-codes the wordpress base URLs.

# File:
# Purpose: Adds a few key elements to wp-config.php
# History 2016-06-20 changed to make entrymod the entry point and it just points to at the end
# Reference:

WP_BLOGDIR=$( echo "${WP_HOME}" | sed 's!https\?://[^/]*!!;' )

function dotask {

rm -rf ${tmpfile1} ${tmpfile2} >/dev/null 2>&1

   sed -n -e '1,/.*define.*DB_NAME.*/p;' ${infile1}
   [[ -n "${WP_HOME}" ]] && echo "define('WP_HOME','${WP_HOME}');"
   [[ -n "${WP_SITEURL}" ]] && echo "define('WP_SITEURL','${WP_SITEURL}');"
   [[ -n "${WP_BLOGDIR}" ]] && {
      echo "\$_SERVER['REQUEST_URI'] = '${WP_BLOGDIR}' . \$_SERVER['REQUEST_URI'];"
      echo "\$_SERVER['SCRIPT_NAME'] = '${WP_BLOGDIR}' . \$_SERVER['SCRIPT_NAME'];"
      #echo "\$_SERVER['PHP_SELF'] = '${WP_BLOGDIR}' . $_SERVER['PHP_SELF'];"

   cat <<'EOF'
   tac ${infile1} | sed -n -e '1,/^define.*DB_NAME.*\|^\# END ADDITIONS/{/^define.*DB_NAME.*\|^\# END ADDITIONS/!p;}' | tac

} > ${tmpfile1}

chmod 0644 ${tmpfile1}
mv ${tmpfile1} ${infile1} >/dev/null 2>&1

{ while [[ ! -f ${infile1} ]]; do echo "waiting for ${infile1} to exist. Sleeping 3." && sleep 3; done; dotask;} &

exec / "$@"

I learned that here-documents can employ variable names without being parsed by bash if you put the end string in quotes, as shown in this script file. Reference: Weblink 5

Running the wordpress install

Now start up the docker-compose.

sudo docker-compose up

Configuring Apache as a reverse proxy

Enable these mods. For ubuntu apache2:

a2enmod xml2enc headers rewrite proxy_http proxy_html proxy

Here is a virtualhost directive.

<VirtualHost *:80>

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        RewriteEngine On

        ProxyPass               /frodo
        ProxyPassReverse        /frodo

        ProxyPass               /bilbo
        ProxyPassReverse        /bilbo



Commands used during my building and testing

Aliases in ~/.bashrc.local

alias dc='/usr/bin/sudo docker-compose'
alias docker='/usr/bin/sudo docker'

Command lines

dc down && docker rmi bilbo_wpmod && sudo rm -rf /var/bilbo
watch 'head -n58 /var/bilbo/www/wp-config.php | tail -n 17'

Adding vim to a docker container

In the wordpress container, to get to the local organization mirror for ubuntu.
Need 3 apt keys, two of which are the main ubuntu keys.

apt-key adv --keyserver --recv-keys 3B4FE6ACC0B21F32 40976EAF437D05B5
curl > /root/my-debian.gpg
apt-key add /root/my-debian.gpg
apt-get update
apt-get install -y vim



  1. Apt-key commands

Reverse proxy for wordpress

I spent the most research time on getting wordpress to work behind a reverse proxy.
I ended up writing my own Dockerfile to make my own image based on the wordpress image, because the entrypoint was not sufficient.

  1. One of the first pages you hit
  2. Eventually I got to the point where main site would work, but the wp-admin pages would redirect to and not include the /blog directory, like this guy who didn’t get it solved.
  3. Similar problems to this guy. He also provided his nginx reverse proxy config.
  4. At some point I had the wp-admin page working but the main site just wasn’t loading at all.
  5. The holy grail is found here by this WordPress genius.
  6. I didn’t use this, but this might be needed in the future: a .htaccess file that I saw referenced in at least one other location.

Internal documents

  1. Dockerizing WordPress in One Container with Apache.docx
  2. Adding the service httpd.docx

Installing docker behind a proxy

Installing docker behind a proxy

If you are trying to install docker behind a proxy, you might run into multiple problems.
The first one is getting the gpg key for apt.
From the install instructions for ubuntu, you see the directive to download the apt key. What they don’t tell you on that page is that you need an extra cli option like so:

sudo apt-key adv --keyserver-options http-proxy= --keyserver hkp:// --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

Pulling images behind a proxy

And then of course since you’re behind that proxy, you might have issues with docker downloading images.
Here are the condensed instructions from the full explanation at the official docker docs.

mkdir /etc/systemd/system/docker.service.d
cat </etc/sytemd/system/docker.service.d/http-proxy.conf
Environment="HTTP_PROXY=" "NO_PROXY=localhost,,"
systemctl daemon-reload
systemctl restart docker


Solve sudo sending useless emails “problem with defaults entries”

sudo problem with defaults entries

I ran into a problem on my Ubuntu 16.04 Server LTS instance.

Whenever a user (whether sssd-ad authenticated user, or local user, or root) uses sudo, it works. But it also sends the administrator a useless email: : Jun  6 14:40:44 : root : problem with defaults entries ; TTY=pts/2 ; PWD=/root ;

I started removing the defaults entries in /etc/sudoers (using the visudo) command one by one, but after removing them all it still sent the annoying emails. Here are the defaults I was working from:

Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

How do I make sudo stop sending me useless emails?

This problem is caused by sudo looking for directives in a place it cannot find them: sss.
Check the /etc/nsswitch.conf file and modify the sudoers entry.

sudoers:        files sss

The sss should not be there. The sssd-ad package adds itself there, but very few environments store sudoers directives in sss. It’s far more likely your directives are local, so you should have a /etc/nsswitch file entry like the following:

sudoers:        files


A user of RHEL6 had the same issue.
The issue is solvable, including on Ubuntu 16.04