Skip to content

Migrating CA using General Mechanism

Endi S. Dewata edited this page Mar 27, 2024 · 3 revisions

Overview

This is a general migration procedure useful for pretty much any migration - and in particular for migrations prior to RHCS 9.1. After 9.1, there are tools and mechanisms available to do this migration more simply and with less manual steps.

The basic idea is to create a new instance - with new system certificates and keys - but then to replace that instance's certificates and keys with those from the old instance.

The exception to this will be the server certificate which must have a subject name that is of the form cn=hostname, and which is probably going to be different in the old and new instances. In this case, we will generate a server cert for the new instance on the OLD instance, and swap out the server cert.

Finally, the data in the internal database from the old system will be migrated to the new instance using the LDAP commands and utilities.

Migration Procedure

Here are the basic steps:

A. On the old instance:

1. Issue a server certificate for the new instance.

To do this, create a new NSS database, generate the CSR and submit to the old CA. Issue the certificate, and store the certificate and key in a PKCS#12 file. The nickname used for the certificate should be the same as the nickname to be used for the server certificate in the new server. To simplify things, I made it different from the nickname for the server certificate on the old server.

   mkdir -p /tmp/serverdb
   cd /tmp/serverdb
   certutil -N -d .
   certutil -R -d . -s "cn=host2.example.com" -Z "SHA256" -a -o "server.csr"
   (submit to old CA and get new cert and store as ascii in server.crt)
   certutil -A -d . -n "Server-Cert cert pki-ca host2.example.com" -t "u,u,u" -a -i server.crt
   pk12util -o servercert.p12 -n "Server-Cert cert pki-ca host2.example.com" -d .

2. Back up the old instance's data. The database name can be found from the old instance's CS.cfg. In the commands below, the output is written to /tmp because the commands run as the database user.



3. Back up the old instances certificate database and password.

   tar chzvf /tmp/nssdb.tar.gz -C /var/lib/pki-ca/alias .
   grep internal= /var/lib/pki-ca/conf/password.conf | awk -F= '{print $2;}' > /tmp/internal.txt

4. Back up the old instance's CS.cfg

   cp /etc/pki-ca/CS.cfg /tmp/old_ca.CS.cfg

5. Transfer the server cert PKCS#12 file, the backed up database and password, the backed up certificate database and the old CS.cfg to the new instance.

B. On the new instance:

1. Modify the shared CS.cfg template at /usr/share/pki/ca/conf/CS.cfg to specify the starting point for the certificate serial number and request numbers.

We want to select the start of the serial and request numbers such that there are no duplicated numbers once the old data is imported. To see which serial numbers to use, I looked at the old CA's agent interface and listed both certificates and request numbers. Assuming the serial numbers are not being assigned randomly, you want a value that is larger than the last number that was issued. For safety sake, I left a bit of a gap between the last issued and the start range. Note that certificate serial numbers are in hex and should be specified without the '0x' prefix. Request numbers are decimals.

In the commands below, we modify the starting certificate and request serial numbers to 0x30 and 50 respectively.

  cp /usr/share/pki/ca/conf/CS.cfg /usr/share/pki/ca/conf/CS.cfg.orig
  sed -i 's/dbs.beginRequestNumber=1/dbs.beginRequestNumber=50/' /usr/share/pki/ca/conf/CS.cfg
  sed -i 's/dbs.beginSerialNumber=1/dbs.beginSerialNumber=30/' /usr/share/pki/ca/conf/CS.cfg

As these template files can be used to create other instances, they should be reverted to their original form once your instance has been migrated.

2. Create a pkispawn configuration file. Make sure the following is specified:-

      The nickname, algorithm and key and subject name for the server cert should
      be the same as the server cert you generated on the old instance in step A1 above.
      
      Here is a sample pkispawn config file:
      [CA]
      pki_ds_base_dn=dc=host2.example.com-pki-ca
      pki_ds_database=host2.example.com-pki-ca
      pki_ssl_server_nickname=Server-Cert cert-pki-ca host2.example.com
      pki_ssl_server_subject_dn=CN=host2.example.com
      pki_subsystem_nickname=subsystemCert cert-pki-ca
      pki_subsystem_subject_dn=CN=CA Subsystem Certificate,OU=pki-ca,o=example.com
      pki_ca_signing_nickname=caSigningCert cert-pki-ca
      pki_ca_signing_subject_dn=CN=Certificate Authority,OU=pki-ca, o=example.com
      pki_ocsp_signing_nickname=ocspSigningCert cert-pki-ca
      pki_ocsp_signing_subject_dn=CN=OCSP Signing Certificate,OU=pki-ca,o=example.com 
      pki_audit_signing_nickname=auditSigningCert cert-pki-ca
      pki_audit_signing_subject_dn=CN=CA Audit Signing Certificate,OU=pki-ca,o= example.com

3. Create a new instance using this config file.

   pkispawn -s CA -i config.cfg

4. Stop the new instance.

   systemctl stop pki-tomcatd@pki-tomcat.service

5. Replace the nssdb with the old one. Make sure that the right password is in password.conf.

   rm /var/lib/pki/pki-tomcat/alias/*
   cd /var/lib/pki/pki-tomcat/alias/
   tar -xvzf ~/old_ca/nssdb.tar.gz .
   NSSPASS=`cat ~/old_ca/internal.txt`
   sed -i "s/internal=.*/internal=${NSSPASS}/" /var/lib/pki/pki-tomcat/conf/password.conf

6. Replace the server cert (unless you're using the same hostname as the old system) using the server cert that you generated on the old server and transferred using a PKCS#12 file.

   (Now add the new server cert and key)
   pk12util -d /var/lib/pki/pki-tomcat/alias -i servercert.p12

7. Fix up the CS.cfg using the values in the old CS.cfg. The values that need to be replaced here are simply those corresponding to the system certificates:

   (and the same for the other system certs, except for the server cert)

I have written a short Python script to help with this task.

 
  1. !/usr/bin/python
  2. Authors:
  3. Ade Lee <alee@redhat.com></alee@redhat.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; version 2 of the License.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with this program; if not, write to the Free Software Foundation, Inc.,
  13. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  14. Copyright (C) 2016 Red Hat, Inc.
  15. All rights reserved.
from import absolute_import import getopt import shutil import sys

import pki

property_keys = [
def print_usage():

<pre>    print &#39;migrate_cs.py &#45;&#45;old &amp;lt&#59;old&amp;gt&#59;&amp;lt&#59;/old&amp;gt&#59; &#45;&#45;new &amp;lt&#59;new_file&amp;gt&#59;&amp;lt&#59;/new_file&amp;gt&#59; &#45;&#45;out &amp;lt&#59;out_file&amp;gt&#59;&#39;
    sys.exit(1)
def]migrate(old_file, out_file):
    old_properties &amp;&#35;61&#59; pki.PropertyFile(old_file)
    old_properties.read()
    new_properties &amp;&#35;61&#59; pki.PropertyFile(out_file)
    new_properties.read()
    for prop_key in property_keys&amp;&#35;58&#59;
        prop_value &amp;&#35;61&#59; old_properties.get(prop_key)
        if prop_value is None&amp;&#35;58&#59;
            continue
        new_properties.set(prop_key, prop_value)
    new_properties.write()

def main():

    try&amp;&#35;58&#59;
        opts, args &amp;&#35;61&#59; getopt.getopt(sys.argv&amp;amp&#59;&amp;&#35;35&#59;91&amp;&#35;59&#59;1&amp;&#35;58&#59;&amp;amp&#59;&amp;&#35;35&#59;93&amp;&#35;59&#59;,&amp;amp&#59;quot&amp;&#35;59&#59;h&amp;amp&#59;quot&amp;&#35;59&#59;,&amp;amp&#59;&amp;&#35;35&#59;91&amp;&#35;59&#59;&amp;amp&#59;quot&amp;&#35;59&#59;old&amp;&#35;61&#59;&amp;amp&#59;quot&amp;&#35;59&#59;,&amp;amp&#59;quot&amp;&#35;59&#59;new&amp;&#35;61&#59;&amp;amp&#59;quot&amp;&#35;59&#59;,&amp;amp&#59;quot&amp;&#35;59&#59;out&amp;&#35;61&#59;&amp;amp&#59;quot&amp;&#35;59&#59;&amp;amp&#59;&amp;&#35;35&#59;93&amp;&#35;59&#59;)
    except getopt.GetoptError&amp;&#35;58&#59;
        print_usage()
    for opt, arg in opts&amp;&#35;58&#59;
        if opt &amp;&#35;61&#59;&amp;&#35;61&#59; &amp;&#35;39&#59;&amp;amp&#59;&amp;&#35;35&#59;45&amp;&#35;59&#59;h&amp;&#35;39&#59;&amp;&#35;58&#59;
            print_usage()
        elif opt &amp;&#35;61&#59;&amp;&#35;61&#59; &amp;amp&#59;quot&amp;&#35;59&#59;&amp;amp&#59;&amp;&#35;35&#59;45&amp;&#35;59&#59;&amp;amp&#59;&amp;&#35;35&#59;45&amp;&#35;59&#59;old&amp;amp&#59;quot&amp;&#35;59&#59;&amp;&#35;58&#59;
            old_file &amp;&#35;61&#59; arg
        elif opt &amp;&#35;61&#59;&amp;&#35;61&#59; &amp;amp&#59;quot&amp;&#35;59&#59;&amp;amp&#59;&amp;&#35;35&#59;45&amp;&#35;59&#59;&amp;amp&#59;&amp;&#35;35&#59;45&amp;&#35;59&#59;new&amp;amp&#59;quot&amp;&#35;59&#59;&amp;&#35;58&#59;
            new_file &amp;&#35;61&#59; arg
        elif opt &amp;&#35;61&#59;&amp;&#35;61&#59; &amp;amp&#59;quot&amp;&#35;59&#59;&amp;amp&#59;&amp;&#35;35&#59;45&amp;&#35;59&#59;&amp;amp&#59;&amp;&#35;35&#59;45&amp;&#35;59&#59;out&amp;amp&#59;quot&amp;&#35;59&#59;&amp;&#35;58&#59;
            out_file &amp;&#35;61&#59; arg
    print &amp;&#35;39&#59;Old CS.cfg file is &amp;&#35;39&#59;, old_file
    print &amp;&#35;39&#59;New CS.cfg file is &amp;&#35;39&#59;, new_file
    print &amp;&#35;39&#59;Output file is &amp;&#35;39&#59;, out_file
    shutil.copy(new_file, out_file)
    migrate(old_file, out_file)

if == "":

    main()

&lt;/nowiki&gt;</out_file>

Execute this as follows:

  cp /var/lib/pki/pki&amp;&#35;45&#59;tomcat/conf/ca/CS.cfg /var/lib/pki/pki&amp;&#35;45&#59;tomcat/conf/ca/CS.cfg.bak
  python migrate_cs.py &amp;&#35;45&#59;&amp;&#35;45&#59;old old_ca_CS.cfg &amp;&#35;45&#59;&amp;&#35;45&#59;new /var/lib/pki/pki&amp;&#35;45&#59;tomcat/conf/ca/CS.cfg &amp;&#35;45&#59;&amp;&#35;45&#59;out new_CS.cfg
  cp new_CS.cfg /var/lib/pki/pki&amp;&#35;45&#59;tomcat/conf/ca/CS.cfg

8. Restore the old directory server data. Detailed instructions are provided here - https://github.com/dogtagpki/pki/wiki/Migrating-CA-using-Existing-CA-Mechanism#Import_the_old_data_into_the_new_CA_database These instructions include a detailed explanation of the output you are likely to encounter.

9. Restore users to their proper groups. As mentioned in the import instructions above, users may need to be re-added to groups as required. In order to do this, one needs to either use ldapmodify commands, or log into the pkiconsole using the newly created caadmin user's password.

Note that it will not be possible to use this user's certificate to make a TLS/SSL connection either through the web or through the pki command line because that user's certificate was issued by the pkispawn-generated CA signing certificate (which we have already discarded).

Once at least one of the old admin users has been restored to the admin group, however, we can use that admin user's certificate to make connections to the web UI and pki CLI.

10. In my case, there were no customized UI, profiles or plugins. These should be added either by copying in the required files or by using the console.

11. The subsystem user does not have the right certificate. It has the subsystem certificate that was generated during pkispawn (and then discarded). Fix this using the console or using the pki command line.

12. Restart the CA.

    systemctl restart pki&amp;&#35;45&#59;tomcatd@pki&amp;&#35;45&#59;tomcat.service
Clone this wiki locally