Git Workflow

Set git username and email:

$ git config --global user2
$ git config --global

Set global log alias – this will allow git glog to show summary, graphical, colour log history:

$ git config --global alias.glog "log --all --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

Create a feature branch using ticket number MTSU-1197 as the branch name

$ git checkout -b MTSU-1197
$ echo “this is a new file” > newfile
$ git add newfile
$ git commit -m “add newfile”
$ git push origin MTSU-1197

Updating feature branch from the master branch

Merge Strategy method

Let’s look at a merge strategy first. We’ll simulate the master branch changing, and a new feature being incorporated before we can finish our feature.

$ git checkout -b master
$ echo “some new feature” > somefile
$ git add somefile
$ git commit -m ‘add a new feature’

Now let’s make some other changes in our feature branch:

$ git checkout MTSU-1197
$ echo “more feature changes” >someotherfile
$ git add someotherfile
$ git commit -m ‘add more feature changes’

Now let’s try and pull the latest changes from the main ‘master’ branch into our feature:

$ git pull . master

Git will pull up a new editor that looks like the following:

Merge branch 'master' into MTSU-1197

# Please enter a commit message to explain why this merge is necessary, especially if it merges an updated upstream into a topic branch.
# Lines starting with '#' will be ignored, and an empty message aborts the commit.

So what’s happened? In this case, Git has created a new ‘merge commit’ in our feature branch that ties the histories of these two branches together. This isn’t necessarily a bad thing – merging branches together is a non-destructive operation, so it retains the history of our changes made.

However, we might not want to many merge commits in our history. If our master branch is changing frequently, we’ll end up with lots of merge commits, which can make our history difficult to read.

Rebase Method

Let’s reset our feature branch using a rebase – we’ll explain more about the
rebase tool in a second.

$ git rebase -i HEAD~2

You’ll see the following:

pick f4f3b23 add more feature changes
pick a28c1d9 add a new feature

# Rebase ff6e2f9..3e69fab onto ff6e2f9 (2 commands)
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
# l, label = label current HEAD with a name
# t, reset = reset HEAD to a label
# m, merge [-C | -c ] [# ]

Let’s drop the second commit. Change:

pick f4f3b23 add more feature changes
pick a28c1d9 add a new feature


pick f4f3b23 add more feature changes
drop a28c1d9 add a new feature

And write the file and quit. You’ll now see that git has rebased your local repo:

Successfully rebased and updated refs/heads/MTSU-1197

Wait, what happened there? Effectively we rewrote Git history by dropping a commit out. We did this using a ‘rebase’ – we took the latest changes in the
master branch, and then replayed commits from our current branch on top. Git’s ‘interactive rebase’ (shown above) let’s us alter how this replay is performed. We can drop or squash commits, for example, when the current branch is replayed.

Rebasing results in a much cleaner project history, but can lead to pitfalls if notused correctly. While it’s normally safe to perform a ‘git pull –rebase’,
as we do below, when we start dropping and squashing commits there’s one
golden rule – don’t rebase a public branch. If someone else can see your code in a branch, then don’t drop, squash or amend commits, it’s safest to just leave it alone.

Now let’s use a rebase strategy to pull in the latest master branch changes. A
rebase involves moving our entire feature branch to begin on the tip of the main branch. Instead of creating a merge commit though, rebasing will create new commits for each commit in our feature branch, effectively rewriting history.

We’ve just reset our feature branch using our ‘interactive rebase’, so we can now rebase our new changes on the latest master branch.

Git pull . master --rebase
From .
 * branch master -> FETCH_HEAD
First, rewinding head to replay your work on top of it…
Applying: add more feature changes

Awesome! Now we have the latest changes from the master branch, and our new code, and we haven’t produced an unnecessary merge commit.

Kickstarting oVirt Node

oVirt Node hypervisors (the old RHEV-H) can be installed by a simple kickstart.

Loop mount the ovirt-node ISO and make the content avialable via HTTP

mkdir /var/www/html/iso/ovirt-node-4.4
mount -o loop /var/www/html/iso/ovirt-node-ng-installer-4.4.2-2020091810.el8.iso /var/www/html/iso/ovirt-node-4.4

Copy the PXELinux bootloader files

cp /var/www/html/iso/ovirt-node-4.4/isolinux/vmlinuz /var/lib/tftpboot/boot/ovirt-node-4.4-vmlinuz
cp /var/www/html/iso/ovirt-node-4.4/isolinux/initrd.img /var/lib/tftpboot/boot/ovirt-node-4.4-initrd.img

Create the PXELinux TFTP config

DEFAULT oVirt Node

LABEL oVirt Node
  KERNEL boot/ovirt-node-4.4-vmlinuz
  APPEND ks= ksdevice=link initrd=boot/ovirt-node-4.4-initrd.img inst.stage2=

Create the kickstart config

# System authorization information
auth --enableshadow --passalgo=sha512

# SELinux configuration
selinux --permissive

# Network information
network  --bootproto=dhcp --device=eno1 --ipv6=auto --activate
network  --bootproto=dhcp --device=eno2 --onboot=off --ipv6=auto
network  --bootproto=dhcp --device=ens5f0 --ipv6=auto --activate --nodefroute
network  --bootproto=dhcp --device=ens5f1 --onboot=off --ipv6=auto
network  --bootproto=dhcp --device=ens5f2 --onboot=off --ipv6=auto --activate
network  --bootproto=dhcp --device=ens5f3 --onboot=off --ipv6=auto

#Root password
rootpw $6$63af2vwMbmowO55d$C4CiNrljZAZbJauVxRdt8QKsbxBZcNZ.mOoKNtkJGD39nOcDh6sVtbC6Iv8JM9h0q9LJT1mhDzrTvcJzvRKff1 --iscrypted
user --name ansible --groups=wheel --password $6$63af2vwMbmowO55d$C4CiNrljZAZbJauVxRdt8QKsbxBZcNZ.mOoKNtkJGD39nOcDh6sVtbC6Iv8JM9h0q9LJT1mhDzrTvcJzvRKff1 --iscrypted

clearpart --all
bootloader --timeout=1
autopart --type=thinp

# Grab image
liveimg --url=""

# non interactive
# text
# Keyboard layouts
# old format: keyboard us
# new format:
keyboard --vckeymap=us --xlayouts=''
# System language
lang en_US.UTF-8

# Shutdown after installation

# System services
services --enabled="chronyd"

# System timezone
timezone Australia/Sydney --isUtc

%post --erroronfail
set -x

# Postprocess (always the last step)
imgbase layout --init


%packages --excludedocs --ignoremissing


%addon com_redhat_kdump --enable --reserve-mb='auto'


Network boot the server, it will magically install oVirt-node and be ready for the next step – installing the Engine.

Enabling SSL CRL checking in Apache

To test client SSL certificates against the issuing CRL, Apache needs an additional configuration directive in the /etc/httpd/conf.d/ssl.conf

SSLCARevocationPath /etc/httpd/conf/ssl.crl/

We then need to create this directory and restart httpd.

Although some SSL certificates contain a URL for the CRL distribution point, Apache will not automatically check this URL. Instead, we must download the CRL and place it in the defined path. The CRL is created in DER format, and needs to be converted to x509 before it can be read by Apache.

The following cron entry can be used to automate this process – place this cron entry into /etc/cron.hourly/update_httpd_crl.cron, and don’t forget to include ALL of the CRL’s relevent to the CA chain of your client certificates.

cd /etc/httpd/conf/ssl.crl
# Download and convert CRL
curl -s <a href=""></a> | openssl crl -inform DER -out root-ca.crl
curl -s <a href=""></a> | openssl crl -inform DER -out tls-ca.crl
# Create required hash links
ln -s root-ca.crl `openssl crl -noout -hash -in root-ca.crl`.r0 2>/dev/null
ln -s tls-ca.crl `openssl crl -noout -hash -in tls-ca.crl`.r0 2>/dev/null
# Perform a graceful restart to re-read the CRL
service httpd graceful

PKI Enabling Nagios

Although it’s not documented very well, Nagios can be made to use Client SSL (PKI) authentication.

There are two main steps required:

1 – Modify /etc/httpd/conf.d/nagios.conf 

In this step we need to comment out the existing AuthType parameters and include the SSLVerifyClient sections to both <Directory> containers:

ScriptAlias /nagios/cgi-bin/ "/usr/lib64/nagios/cgi-bin/"
<Directory "/usr/lib64/nagios/cgi-bin/">
#  SSLRequireSSL
   Options ExecCGI
   AllowOverride None
   Order allow,deny
   Allow from all
#  AuthName "Nagios Access"
#  AuthType Basic
#  AuthUserFile /etc/nagios/passwd
#  Require valid-user
   # We're going to use SSL Certs for authentication
   SSLVerifyClient optional
   RewriteEngine On
   RewriteRule .* /ssl-client-auth-required.html [L]
Alias /nagios "/usr/share/nagios/html"
<Directory "/usr/share/nagios/html">
#  SSLRequireSSL
   Options FollowSymLinks
   AllowOverride None
   Order allow,deny
   Allow from all
#  AuthName "Nagios Access"
#  AuthType Basic
#  AuthUserFile /etc/nagios/passwd
#  Require valid-user
   # We're going to use SSL Certs for authentication
   SSLVerifyClient optional
   RewriteEngine On
   RewriteRule .* /ssl-client-auth-required.html [L]

This relies on the main /etc/httpd/conf.d/ssl.conf being configured to enable SSL, although the site-wide SSLVerifyClient statements do not need to be defined. These can be defined on a per <Location> or <Directory> basis if required – in this example the remainder of the server is available to standard SSL, whilst Nagios requires a PKI cert.

Whilst testing this setup I also found that I needed to change Options None to OptionsFollowSymLinks in the second <Directory> block, otherwise Chrome refused to login using the client certificate.

The steps above should result in a certificate challenge when accessing the Nagios URL (after a httpd restart), and on selecting the appropriate certificate you should be logged in.

2 – Grant Nagios Authorizations 

To get permission to DO anything in Nagios, you will need to edit /etc/nagios/cgi.cfg and add the CN from the certificate(s) to the relevent authorization statements, which use comma seperated values, so spaces in the CN are OK.

PKI Enabling an Apache Web Server

Once all of the required SSL certificates have been created (or obtained via enterprise channels) it is relatively easy to enable Client-side SSL authentication on an Apache webserver.

The server needs to have mod_ssl installed, and the site needs to be set up to use SSL. The important bits here are that the various SSLCertificate options are set correctly to use locally installed copies of the published CA and Server Certificates.

This is an example <VirtualHost> container in /etc/httpd/conf.d/ssl.conf that implements a signed SSL chain to verify the Server. It enforces Client PKI in that without a valid client certificate, access to the SSL website is denied.

<VirtualHost *:443>
    # Use separate log files for the SSL virtual host; note that LogLevel is not inherited from httpd.conf.
    ErrorLog logs/ssl_error_log
    TransferLog logs/ssl_access_log
    LogLevel warn
    # Enable SSL for this virtual host.
    SSLEngine on
    SSLProtocol all -SSLv2
    # Server Certificate:
    SSLCertificateFile /etc/pki/tls/certs/
    SSLCertificateKeyFile /etc/pki/tls/private/
    SSLCertificateChainFile /etc/pki/tls/certs/tls-ca-chain.pem
    SSLCACertificateFile /etc/pki/tls/certs/tls-ca-chain.pem
    # Client Authentication:
    SSLVerifyClient optional
    SSLVerifyDepth  4
    # If Client Certificate is not valid, send user to an error page.
    RewriteEngine On
    RewriteRule .* /ssl-client-auth-required.html [L]
    # Allow extraction of attributes from user certificates
    # SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
    <Files ~ "\.(cgi|shtml|phtml|php3?)$">
        SSLOptions +StdEnvVars
    <Directory "/var/www/cgi-bin">
        SSLOptions +StdEnvVars
    # SSL Protocol Adjustments:
    SetEnvIf User-Agent ".*MSIE.*"nokeepalive ssl-unclean-shutdowndowngrade-1.0 force-response-1.0
    # Per-Server Logging:
    CustomLog "|/usr/sbin/rotatelogs /var/log/httpd/ssl_request_log 720""%h %l %{SSL_CLIENT_S_DN_CN}x %t %r %>s %b"

The configuration above states that SSLVerifyClient is OPTIONAL. We have configured this particular server in a way that despite the requirement for a client cert being optional, it’s actually mandatory. The way this works is if we set SSLVerifyClient to REQUIRE, the session would terminate instantly on detection of an invalid certificate. Instead, we trap the fact that the cert is invalid in the RewriteCond statement, and redirect the user to an appropriate error page stating that PKI authentication is required.

The SSLUserName option populates the Apache REMOTE_USER variable with the CN from the certificate. We can set this to any available attribute, and the REMOTE_USER is a hook available to CGI/Perl/PHP pages to use for authorization if required. We also pull out the user’s CN from the client certificate and poke it into a custom formatted log entry.

Signing a Server Certificate

Create a key

Our root and intermediate pairs are 4096 bits. Server and client certificates normally expire after one year, so we can safely use 2048 bits instead.

cd /etc/pki/CA
openssl genrsa -aes256 \
-out intermediate/private/ 2048

chmod 400 intermediate/private/

Create a certificate

Use the private key to create a certificate signing request (CSR). The CSR details don’t need to match the intermediate CA. For server certificates, the Common Name must be a fully qualified domain name (eg,, whereas for client certificates it can be any unique identifier (eg, an e-mail address). Note that the Common Name cannot be the same as either your root or intermediate certificate.

cd /etc/pki/CA
openssl req -config intermediate/openssl.cnf \
-key intermediate/private/ \
-new -sha256 -out intermediate/csr/  
Enter pass phrase for secretpasswordYou are about to be asked to enter information that will be incorporated
into your certificate request.
Country Name (2 letter code) [AU]:
State or Province Name [New South Wales]:
Locality Name []:
Organization Name [GatwardIT]:
Organizational Unit Name []:GatwardIT Web Services
Common Name []
Email Address []:

To create a certificate, use the intermediate CA to sign the CSR. If the certificate is going to be used on a server, use the server_cert extension. If the certificate is going to be used for user authentication, use the usr_cert extension. Certificates are usually given a validity of one year, though a CA will typically give a few days extra for convenience.

If we want to allow alternative DNS matches for the certificate we can use the SubjectAltNames section to define them.
Our config file has a section that will populate the SubjectAltNames section with the content of the environment variable SAN.

cd /etc/pki/CA
openssl ca -config intermediate/openssl.cnf \
-extensions server_cert -days 375 -notext -md sha256 \
-in intermediate/csr/ \
-out intermediate/certs/
chmod 444 intermediate/certs/

Verify the certificate

openssl x509 -noout -text \
-in intermediate/certs/

Use the CA certificate chain file we created earlier (GatwardIT-chain.pem) to verify that the new certificate has a valid chain of trust.

openssl verify -CAfile intermediate/certs/GatwardIT-chain.pem \

Signing IPA certitificate

We can have the IPA server CA signed by our root CA.

Perform the IPA server installation using the –external-ca option. This will create the /root/ipa.csr signing request on the IPA server – copy this to the CA server for signing.

scp /root/ipa.csr caserver:/etc/pki/CA/intermediate/csr

Sign the IPA CA

We will sign the IPA request using the v3_intermediate_ca rules, but also using the policy_loose policy. The IPA CSR will not contain all mandatory fields for a root CA, so the loose policy we defined allows these to be optional.

openssl ca -config openssl.cnf -extensions v3_intermediate_ca \
  -days 3650 -notext -md sha256 \
  -policy policy_loose \
  -in intermediate/csr/ipa.csr \
  -out intermediate/certs/ipa.pem

Installing the certs into IPA

Transfer the signed certificate (intermediate/certs/ipa.pem) back to the IPA server, along with the root CA (certs/GatwardIT-CA2.pem), and continue the IPA installation using:

ipa-server-install --external-cert-file=/root/ipa.pem \

Intermediate Signing CA

An intermediate certificate authority (CA) is an entity that can sign certificates on behalf of the root CA. The root CA signs the intermediate certificate, forming a chain of trust.

The purpose of using an intermediate CA is primarily for security. The root key can be kept offline and used as infrequently as possible. If the intermediate key is compromised, the root CA can revoke the intermediate certificate and create a new intermediate cryptographic pair.

Prepare the directory

The root CA files are kept in /etc/pki/CA. Choose a different directory (/etc/pki/CA/intermediate) to store the intermediate CA files.

mkdir /etc/pki/CA/intermediate

Create the same directory structure used for the root CA files. It’s convenient to also create a csr directory to hold certificate signing requests.

cd /etc/pki/CA/intermediate
mkdir certs crl csr newcerts private
chmod 700 private
touch index.txt
echo 01 > serial

Add a crlnumber file to the intermediate CA directory tree. crlnumber is used to keep track of certificate revocation lists.

echo 01 > /etc/pki/CA/intermediate/crlnumber

Copy the intermediate CA configuration file from /etc/pki/CA/openssl.cnf to /etc/pki/CA/intermediate/openssl.cnf.
The following options have been changed compared to the root CA configuration file:

[ default ]
ca              = GatwardIT-TLS
SAN             = DNS:somesite.tld
[ CA_default ]
dir             = /etc/pki/CA/intermediate
policy          = policy_loose
[ server_cert ]
subjectAltName  = $ENV::SAN

Create the intermediate key

Create the intermediate key (GatwardIT-TLS.key). Encrypt the intermediate key with AES 256-bit encryption and a strong password.

cd /etc/pki/CA
openssl genrsa -aes256 \
-out intermediate/private/GatwardIT-TLS.key 4096 
Enter pass phrase for intermediate.key: secretpassword
Verifying - Enter pass phrase for intermediate.key: secretpassword 
chmod 400 intermediate/private/*.key

Create the intermediate certificate

Use the intermediate key to create a certificate signing request (CSR). The details should generally match the root CA. The Common Name, however, must be different.

cd /etc/pki/CA
openssl req -config intermediate/openssl.cnf -new -sha256 \
-key intermediate/private/GatwardIT-TLS.key \
-out intermediate/csr/GatwardIT-TLS.csr 
Enter pass phrase for intermediate.key: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
Country Name (2 letter code) [AU]:
State or Province Name [New South Wales]:
Locality Name []:
Organization Name [GatwardIT]:
Organizational Unit Name []:GatwardIT Certificate Authority
Common Name []:GatwardIT TLS CA
Email Address []:

To create an intermediate certificate, use the root CA with the v3_intermediate_ca extension to sign the intermediate CSR. The intermediate certificate should be valid for a shorter period than the root certificate. Ten years would be reasonable.

cd /etc/pki/CA
openssl ca -config openssl.cnf -extensions v3_intermediate_ca \
-days 3650 -notext -md sha256 \
-in intermediate/csr/GatwardIT-TLS.csr \
-out intermediate/certs/GatwardIT-TLS.pem 
Enter pass phrase for GatwardIT-CA2.key: secretpassword
Sign the certificate? [y/n]: y 
chmod 444 intermediate/certs/*.pem

Verify the intermediate certificate

As we did for the root certificate, check that the details of the intermediate certificate are correct.

openssl x509 -noout -text -in intermediate/certs/GatwardIT-TLS.pem

Verify the intermediate certificate against the root certificate. An OK indicates that the chain of trust is intact.

openssl verify -CAfile certs/GatwardIT-CA2.pem \

Create the certificate chain file

When an application (eg, a web browser) tries to verify a certificate signed by the intermediate CA, it must also verify the intermediate certificate against the root certificate. To complete the chain of trust, create a CA certificate chain to present to the application.

To create the CA certificate chain, concatenate the intermediate and root certificates together. We will use this file later to verify certificates signed by the intermediate CA.

cat intermediate/certs/GatwardIT-TLS.pem \
certs/GatwardIT-CA2.pem > intermediate/certs/GatwardIT-chain.pem
chmod 444 intermediate/certs/*.pem

Create initial CRL

A certificate revocation list (CRL) provides a list of certificates that have been revoked. A client application, such as a web browser, can use a CRL to check a server’s authenticity. A server application, such as Apache or OpenVPN, can use a CRL to deny access to clients that are no longer trusted.

# cd /etc/pki/CA
# openssl ca -config intermediate/openssl.cnf \
-gencrl -out intermediate/crl/GatwardIT-TLS.crl

You can check the contents of the CRL with the crl tool.

openssl crl -in intermediate/crl/GatwardIT-TLS.crl -noout -text

You should re-create the CRL at regular intervals. By default, the CRL expires after 30 days. This is controlled by the default_crl_days option in the [ CA_default ] section.

Self Signed root CA

First step was to spin up a dedicated minimal spec VM to host the CA. This is to be powered off once the root and signing CAs have been created, to protect the security of the CA itself.

We’re calling the new CA   ‘GatwardIT CA2’

Prepare the directory

Choose a directory (/etc/pki/CA) to store all keys and certificates. Create the directory structure. The index.txt and serial files act as a flat file database to keep track of signed certificates.

cd /etc/pki/CA
mkdir certs crl newcerts private
chmod 700 private
touch index.txt
echo 01 > serial

Create OpenSSL configuration

The [ default ] section is where we can define some global default variables for our configuration.
Here we are setting the name of the CA that will be used in all of the generated files.

[ default ]
ca = GatwardIT-CA2

The [ ca ] section is mandatory. Here we tell OpenSSL to use the options from the [ CA_default ] section.

[ ca ]
# `man ca`
default_ca = CA_default

The CA_default section defines the defaults for our CA (go figure)

[ CA_default ]
# Directory and file locations.
dir               = /etc/pki/CA
certs             = $dir/certs
crl_dir           = $dir/crl
new_certs_dir     = $dir/newcerts
database          = $dir/index.txt
serial            = $dir/serial
RANDFILE          = $dir/private/.rand
# The root key and root certificate.
private_key       = $dir/private/$ca.key
certificate       = $dir/certs/$ca.pem
# For certificate revocation lists.
crlnumber         = $dir/crlnumber
crl               = $dir/crl/$ca.crl
crl_extensions    = crl_ext
default_crl_days  = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md        = sha256
name_opt          = ca_default
cert_opt          = ca_default
default_days      = 375
preserve          = no
policy            = policy_strict

We’ll apply policy_strict for all root CA signatures, as the root CA is only being used to create intermediate CAs.

[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

We’ll apply policy_loose for all intermediate CA signatures, as the intermediate CA is signing server and client certificates that may come from a variety of third-parties.

[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

Options from the [ req ] section are applied when creating certificates or certificate signing requests.

[ req ]
# Options for the `req` tool (`man req`).
default_bits        = 2048
distinguished_name  = req_distinguished_name
string_mask         = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md          = sha256
# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca

The [ req_distinguished_name ] section declares the information normally required in a certificate signing request. You can optionally specify some defaults.

[ req_distinguished_name ]
# See <>.
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name
localityName                    = Locality Name
0.organizationName              = Organization Name
organizationalUnitName          = Organizational Unit Name
commonName                      = Common Name
emailAddress                    = Email Address
# Optionally, specify some defaults.
countryName_default             = AU
stateOrProvinceName_default     = New South Wales
localityName_default            =
0.organizationName_default      = GatwardIT
#organizationalUnitName_default =
#emailAddress_default           =

The next few sections are extensions that can be applied when signing certificates. For example, passing the -extensions v3_ca command-line argument will apply the options set in [ v3_ca ].

We’ll apply the v3_ca extension when we create the root certificate.

[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

We’ll apply the v3_ca_intermediate extension when we create the intermediate certificate. pathlen:0 ensures that there can be no further certificate authorities below the intermediate CA.

[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

We’ll apply the usr_cert extension when signing client certificates, such as those used for remote user authentication.

[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
crlDistributionPoints = URI:$ca.crl

We’ll apply the server_cert extension when signing server certificates, such as those used for web servers.

[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
crlDistributionPoints = URI:$ca.crl

The crl_ext extension is automatically applied when creating certificate revocation lists.

[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).

We’ll apply the ocsp extension when signing the Online Certificate Status Protocol (OCSP) certificate.

[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

Create the root key

Create the root key (GatwardIT-CA2.key) and keep it absolutely secure. Anyone in possession of the root key can issue trusted certificates. Encrypt the root key with AES 256-bit encryption and a strong password.

cd /etc/pki/CA
openssl genrsa -aes256 -out private/GatwardIT-CA2.key 8176
chmod 400 private/*.key

Create the root certificate

Use the root key (GatwardIT-CA2.key) to create a root certificate (GatwardIT-CA2.pem). Give the root certificate a long expiry date, such as twenty years. Once the root certificate expires, all certificates signed by the CA become invalid.

cd /etc/pki/CA
openssl req -config openssl.cnf \
      -key private/GatwardIT-CA2.key \
      -new -x509 -days 7300 -sha256 -extensions v3_ca \
      -out certs/GatwardIT-CA2.pem
Enter pass phrase for GatwardIT-CA2.key: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
Country Name (2 letter code) [AU]:
State or Province Name [New South Wales]:
Locality Name []:
Organization Name [GatwardIT]:
Organizational Unit Name []:GatwardIT Certificate Authority 2
Common Name []:GatwardIT CA2
Email Address []:
# chmod 444 certs/*.pem

Stop Satellite 6 from messing up host NIC definitions

Have you ever provisioned a host with a specific interface configuration in Satellite, only to try to reprovision that host later and have it fail because some application has reconfigured the NIC’s post-deployment and Satellite is now polluted with virtual and/or invalid NIC information?

This happened to me whilst messing with RHV (ovirt) – during the configuration of RHV many additional interfaces were created on my hosts, and when I tried to re-kickstart them from Satellite it just complained about the 20+ virtual interfaces that RHV had created, and my primary interface had been changed to the ovirtmgmt bridge – kickstart on a bridge doesn’t work so well…  Turns out if you create an interface in RHV called ‘traffic’ then you will have that as an interface in Satellite.
If it’s VLAN tagged then you’ll have the tagged interfaces such as traffic.11  traffic.12  etc as well.  Gets messy real quick – thanks facter 🙂

Since I used a common base kickstart to build my hosts, puppet was installed even though I am not using it to deploy any configurations. Puppet itself has facter as a dependency, and so when puppet calls home to Satellite it reports the facts gathered as well, which then update the host details in Satellite.

There are a couple of ways to get around this problem… The first is to simply not install puppet on the hosts – no puppet, no report. But in many cases puppet may actually be wanted/needed to deploy classes required by an enterprise for security.

Thankfully we can address this particular annoyance on the Satellite side. In Satellite, under Settings -> Provisioning is an option to ‘Ignore Puppet facts for provisioning‘. The default is NO. Setting this to YES causes Satellite to ignore any interface facts sent by Puppet, so your provisioning configuration doesn’t get screwed up.

This also applies to the installed OS – ever had it where you kickstatred with 7.3 but after the system upgrades to 7.4 and you try to reprovision, you have some weird OS version mismatch in Satellite because part of the host record is 7.4 but the provisioning record is still 7.3?  Yep – this one had been annoying me for some time with various Satellite installations, time to stop it for good.  Again, under Settings -> Provisioning is the option to ‘Ignore facts for operating system‘. Once more the default in NO, but changing this will stop version updates on the host from changing the Satellite records, so re-provisioning will ‘just work’ without version conflict errors, provided the original OS version is still available for use. (You should, of course, update the host records in Satellite to use the latest versions)

Alternatively, if you know in advance what the naming conventions for the virtual NICs is going to be (you are deploying into a development/QA environment first, right?) you can add them to the ‘ignore interfaces with matching identifier‘ parameter, which already has interface prefixes for Openstack (qvo/qbr/tap etc). All you will need to do is to add the interface prefixes that you will be using in RHV to this list.

Note that these parameter changes are GLOBAL so be careful – however I can’t see too many instances where you want your known provisioning state in Satellite to be modified without your knowledge….