Skip to content

Instantly share code, notes, and snippets.

@seanw2020
Last active February 19, 2024 03:15

Revisions

  1. Sean Wingert revised this gist Nov 14, 2019. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,5 @@
    # How to configure an SSH CA, with visuals
    ![configure certifcate authorities on server and host](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/configure-CAs.png)
    ![sign and use certificates](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/sign-and-use-certs.png)
    ![ssh certificates](https://gist.githubusercontent.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/452958a73183bad1f76346811c485a8d85bf7cdd/configure-CAs.png)

    ## SSH CA
    For details, see "Mastering SSH", Second Edition, Chapter 14: Certificate Authorities. Also see 'man ssh-keygen': "ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).
  2. Sean Wingert revised this gist Sep 27, 2019. 1 changed file with 36 additions and 36 deletions.
    72 changes: 36 additions & 36 deletions ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -26,11 +26,11 @@ sudo ssh-keygen -t rsa -b 4096 -C "SSH CA for users created September 25, 2019 b
    sudo chmod 400 /usr/local/sshca/{hosts-ca,users-ca} # only allow the owner to read these
    sudo chmod 444 /usr/local/sshca/{users-ca.pub,hosts-ca.pub}

    # Upload the users CA to the server. This overwrites the destination!
    scp -P 22 /usr/local/sshca/users-ca.pub root@server:/etc/ssh/
    # Upload the users CA to the server1. This overwrites the destination!
    scp /usr/local/sshca/users-ca.pub root@server1:/etc/ssh/

    # Copy the hosts CA's pub key. This overwrites the destination!
    scp -P 22 /usr/local/sshca/hosts-ca.pub root@client:/etc/ssh/
    scp /usr/local/sshca/hosts-ca.pub root@client1:/etc/ssh/
    ```

    ### SSH Server (sshd)
    @@ -40,8 +40,8 @@ Configure the ssh server to trust the users CA, and thus any certs it signs. We'
    # Log into the CA computer.
    ssh you@ca

    # Update server's sshd_config
    ssh -p 22 root@server bash <<\EOF
    # Update server1's sshd_config
    ssh root@server1 bash <<\EOF
    comment="# Added by configuration-manager@foo.com"
    keyword_pair="TrustedUserCAKeys /etc/ssh/users-ca.pub"
    path="/etc/ssh/sshd_config"
    @@ -59,25 +59,24 @@ EOF
    ```

    ### SSH Client (ssh)
    Configure the ssh client to trust the hosts CA, and thus any certs it signs. We'll use root to modify /etc/ssh.
    Configure the ssh client to trust the hosts CA, and thus any certs it signs. We'll use root to modify /etc/ssh.

    ```bash
    # Log into the CA computer.
    ssh you@ca

    # Create or update the client's /etc/ssh/ssh_known_hosts. By default, it doesn't exist.
    ssh root@client -p 22 bash <<\OUTER
    # Create or update client1's /etc/ssh/ssh_known_hosts. By default, it doesn't exist.
    ssh root@client1 bash <<\OUTER
    # set permissions
    chmod 774 /etc/ssh/ssh_known_hosts
    chmod 774 /etc/ssh/hosts-ca.pub
    # Allow the client to connect to servers from these domains
    # Allow client1 to connect to servers from these domains
    tee -a /etc/ssh/ssh_known_hosts <<INNER
    # Added by configuration-manager@foo.com
    @cert-authority \*.domain1.com,\*.domain2.com $(cat /etc/ssh/hosts-ca.pub)
    INNER
    OUTER

    ```

    ### Sign an ssh server's public keys using hosts-ca
    @@ -86,20 +85,20 @@ OUTER
    ssh you@ca

    # For clarity, create a directory to hold the ssh server's public keys
    mkdir -p /usr/local/sshca/hosts/server
    mkdir -p /usr/local/sshca/hosts/server1

    # Download the public certs
    # Alternatively, ssh-keyscan works but would allow man-in-the-middle.
    scp -P 22 root@server:/etc/ssh/ssh_host_\{rsa_key.pub,dsa_key.pub,ecdsa_key.pub,ed25519_key.pub\} /usr/local/sshca/hosts/server/
    scp root@server1:/etc/ssh/ssh_host_\{rsa_key.pub,dsa_key.pub,ecdsa_key.pub,ed25519_key.pub\} /usr/local/sshca/hosts/server1/

    # Sign all of server's public keys, thus creating certificates with extension .pub
    sudo ssh-keygen -s /usr/local/sshca/hosts-ca -I "i am server" -h -n server,server.foo.com,192.168.0.1 -V +56w5d /usr/local/sshca/hosts/server/ssh_host_*.pub
    # Sign all of server1's public keys, thus creating certificates with extension .pub
    sudo ssh-keygen -s /usr/local/sshca/hosts-ca -I "i am server1" -h -n server1,server1.foo.com,192.168.0.1 -V +56w5d /usr/local/sshca/hosts/server1/ssh_host_*.pub

    # Copy all server's newly signed certs back to server
    scp -P 22 /usr/local/sshca/hosts/server/ssh_host_*-cert.pub root@server:/etc/ssh/
    # Copy all server1's newly signed certs back to server1
    scp /usr/local/sshca/hosts/server1/ssh_host_*-cert.pub root@server1:/etc/ssh/

    # Add the signed certs to sshd_config
    ssh root@server -p 22 bash <<\EOF
    ssh root@server1 bash <<\EOF
    comment="# Added by configuration-manager@foo.com"
    path="/etc/ssh/sshd_config"
    @@ -129,33 +128,33 @@ ssh you@ca
    mkdir -p /usr/local/sshca/users/user1

    # Download the user's public cert
    scp -P 22 user1@client:/home/user1/.ssh/id_rsa.pub /usr/local/sshca/users/user1/
    scp user1@client1:/home/user1/.ssh/id_rsa.pub /usr/local/sshca/users/user1/

    # Sign the user's public key, thus creating a certificate named id_rsa-cert.pub
    # Note: the user mentioned in the -n option must exist on the ssh server and allow logins
    sudo ssh-keygen -s /usr/local/sshca/users-ca -I "user1@foo.com" -n "user1" -V +52w \
    # Note: the user mentioned in the -n option must exist on the ssh server and allow ssh connections
    sudo ssh-keygen -s /usr/local/sshca/users-ca -I "user1@client1" -n "user1" -V +52w \
    /usr/local/sshca/users/user1/id_rsa.pub

    # Optionally investigate the cert's details:
    ssh-keygen -Lf /usr/local/sshca/users/user1/id_rsa-cert.pub

    # Copy the signed certificate back to the user's .ssh directory
    scp -P 22 /usr/local/sshca/users/user1/id_rsa-cert.pub user1@client:/home/user1/.ssh/
    scp /usr/local/sshca/users/user1/id_rsa-cert.pub user1@client1:/home/user1/.ssh/

    # Test from the ssh client.
    ssh user1@client
    ssh -vvv server # You should NOT be prompted. Troubleshoot otherwise. Use ssh-agent for any priv key passwords.
    ssh user1@client1
    ssh -vvv server1 # You should NOT be prompted. Troubleshoot otherwise. Use ssh-agent for any priv key passwords.
    ```

    ## Single-purpose Keys
    This allows you to create a certificate whose public key can only perform one task, like running /usr/local/scripts/myscript.sh. The intention here is for `user1` to run `sudo /usr/local/bin/myscript.sh`.

    ```bash
    # Log into the client
    ssh user1@client
    # Log into client1
    ssh user1@client1

    # Create a new keypair
    ssh-keygen -t rsa -b 4096 -C "user1@foo.com: single purpose key: sudo myscript.sh" -f /home/user1/.ssh/id_rsa-myscript
    ssh-keygen -t rsa -b 4096 -C "user1@client1: single purpose key: sudo myscript.sh" -f /home/user1/.ssh/id_rsa-myscript

    # Try this key when connecting
    tee -a /home/user1/.ssh/config <<\EOF
    @@ -167,29 +166,30 @@ EOF
    chmod 700 /home/user1/.ssh/config

    # Log into CA
    ssh user1@client
    ssh user1@client1

    # Set up a directory
    mkdir -p /usr/local/sshca/users/user1

    # Download the pub key
    scp -P 22 user1@client:/home/user1/.ssh/id_rsa-myscript.pub /usr/local/sshca/users/user1/
    scp user1@client1:/home/user1/.ssh/id_rsa-myscript.pub /usr/local/sshca/users/user1/

    # Sign it
    # NOTE: permit-pty helps troubleshooting (you can see error output) and avoids "PTY allocation request failed on channel 0".
    # NOTE: For details, see ForceCommand and permit-pty in man sshd_config
    sudo ssh-keygen -s /usr/local/sshca/users-ca -I "signed: user@foo.com: single purpose key: myscript.sh" \
    -n "user1" -V +52w -O clear -O permit-pty -O force-command="/usr/local/bin/myscript.sh" \
    # NOTES: permit-pty helps troubleshooting (you can see error output) and avoids "PTY allocation request failed on channel 0".
    # : For details, see ForceCommand and permit-pty in man sshd_config
    # : -n means approved (for login) principals. They are expected to exist on server1 (or configure AuthorizedPrincipalsFile)
    sudo ssh-keygen -s /usr/local/sshca/users-ca -I "signed: user1@client1: single purpose key: myscript.sh" \
    -n "user1,user1@foo.com" -V +52w -O clear -O permit-pty -O force-command="/usr/local/bin/myscript.sh" \
    /usr/local/sshca/users/user1/id_rsa-myscript.pub

    # Optionally inspect it
    ssh-keygen -Lf /usr/local/sshca/users/user1/id_rsa-myscript-cert.pub

    # Upload to client
    scp -P 22 /usr/local/sshca/users/user1/id_rsa-myscript-cert.pub user1@client:/home/user1/.ssh/
    # Upload to client1
    scp /usr/local/sshca/users/user1/id_rsa-myscript-cert.pub user1@client1:/home/user1/.ssh/


    # Test it
    ssh user1@client
    ssh server
    ssh user1@client1
    ssh server1
    ```
  3. Sean Wingert revised this gist Sep 26, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # How to configure an SSH CA, with visuals
    [image1](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/configure-CAs.png)
    [image1](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/sign-and-use-certs.png)
    ![configure certifcate authorities on server and host](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/configure-CAs.png)
    ![sign and use certificates](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/sign-and-use-certs.png)

    ## SSH CA
    For details, see "Mastering SSH", Second Edition, Chapter 14: Certificate Authorities. Also see 'man ssh-keygen': "ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).
  4. Sean Wingert revised this gist Sep 26, 2019. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,6 @@
    # How to configure an SSH CA, with visuals
    [image1](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/configure-CAs.png)
    [image1](https://gist.github.com/seanw2020/5035ca7036ac899dd3142cb004aefb34/raw/f68bf11491d563b6bfaaeb60d13e4501eb1d0f6d/sign-and-use-certs.png)

    ## SSH CA
    For details, see "Mastering SSH", Second Edition, Chapter 14: Certificate Authorities. Also see 'man ssh-keygen': "ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).
  5. Sean Wingert revised this gist Sep 26, 2019. 2 changed files with 0 additions and 0 deletions.
    Binary file removed configure-CAs.png
    Binary file not shown.
    Binary file removed sign-and-use-certs.png
    Binary file not shown.
  6. Sean Wingert revised this gist Sep 26, 2019. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,4 @@
    # How to configure an SSH CA, with visuals
    ![image1](https://gist.github.com/seanw2020/924c50e4c8428ad2d030db99cc819e20/raw/b4bd840660d349c8b2399397aab8fadab45479c6/img/configure-CAs.png)
    ![image1](https://gist.github.com/seanw2020/924c50e4c8428ad2d030db99cc819e20/raw/b4bd840660d349c8b2399397aab8fadab45479c6/img/sign-and-use-certs.png)

    ## SSH CA
    For details, see "Mastering SSH", Second Edition, Chapter 14: Certificate Authorities. Also see 'man ssh-keygen': "ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).
  7. Sean Wingert revised this gist Sep 26, 2019. 2 changed files with 0 additions and 0 deletions.
    File renamed without changes
    File renamed without changes
  8. Sean Wingert revised this gist Sep 26, 2019. 3 changed files with 2 additions and 1 deletion.
    File renamed without changes
    File renamed without changes
    3 changes: 2 additions & 1 deletion ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    # How to configure an SSH CA, with visuals
    ![image1](https://gist.github.com/alienlebarge/605560c2961cb3025038/raw/b75d209134f0fb64f04a5ee9ff274ceabf6e26e8/dodgetocat_v2.png)
    ![image1](https://gist.github.com/seanw2020/924c50e4c8428ad2d030db99cc819e20/raw/b4bd840660d349c8b2399397aab8fadab45479c6/img/configure-CAs.png)
    ![image1](https://gist.github.com/seanw2020/924c50e4c8428ad2d030db99cc819e20/raw/b4bd840660d349c8b2399397aab8fadab45479c6/img/sign-and-use-certs.png)

    ## SSH CA
    For details, see "Mastering SSH", Second Edition, Chapter 14: Certificate Authorities. Also see 'man ssh-keygen': "ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).
  9. Sean Wingert revised this gist Sep 26, 2019. 3 changed files with 3 additions and 0 deletions.
    Binary file added configure-CAs.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added sign-and-use-certs.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    3 changes: 3 additions & 0 deletions ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    # How to configure an SSH CA, with visuals
    ![image1](https://gist.github.com/alienlebarge/605560c2961cb3025038/raw/b75d209134f0fb64f04a5ee9ff274ceabf6e26e8/dodgetocat_v2.png)

    ## SSH CA
    For details, see "Mastering SSH", Second Edition, Chapter 14: Certificate Authorities. Also see 'man ssh-keygen': "ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).

  10. seanw2020 created this gist Sep 26, 2019.
    191 changes: 191 additions & 0 deletions ssh-ca.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,191 @@
    ## SSH CA
    For details, see "Mastering SSH", Second Edition, Chapter 14: Certificate Authorities. Also see 'man ssh-keygen': "ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).

    ### Create two CAs
    Choose a computer to act as the CA. We'll call this the CA computer (not CA host, since "host" is overloaded here). In this example, only root can sign keys, thus sudo.

    ```bash
    # Log into the CA computer.
    ssh you@ca

    # Prepare
    sudo mkdir -p /usr/local/sshca/{users,hosts}
    sudo chmod 1771 /usr/local/sshca # sticky bit (first 1) prevents non-owners from renaming files. # 11 allows cat of .pub files
    sudo chmod 774 /usr/local/sshca/{users,hosts}
    sudo chgrp -R $(id -g -n) /usr/local/sshca # recursively change group to your group

    # Create two CAs: 1 to sign hosts and 1 to sign users. These are openssh, not openssl, CAs
    sudo ssh-keygen -t rsa -b 4096 -C "SSH CA for hosts created September 25, 2019 by John Smith" -f /usr/local/sshca/hosts-ca
    sudo ssh-keygen -t rsa -b 4096 -C "SSH CA for users created September 25, 2019 by John Smith" -f /usr/local/sshca/users-ca

    # Protect them
    sudo chmod 400 /usr/local/sshca/{hosts-ca,users-ca} # only allow the owner to read these
    sudo chmod 444 /usr/local/sshca/{users-ca.pub,hosts-ca.pub}

    # Upload the users CA to the server. This overwrites the destination!
    scp -P 22 /usr/local/sshca/users-ca.pub root@server:/etc/ssh/

    # Copy the hosts CA's pub key. This overwrites the destination!
    scp -P 22 /usr/local/sshca/hosts-ca.pub root@client:/etc/ssh/
    ```

    ### SSH Server (sshd)
    Configure the ssh server to trust the users CA, and thus any certs it signs. We'll use root to modify /etc/ssh.

    ```bash
    # Log into the CA computer.
    ssh you@ca

    # Update server's sshd_config
    ssh -p 22 root@server bash <<\EOF
    comment="# Added by configuration-manager@foo.com"
    keyword_pair="TrustedUserCAKeys /etc/ssh/users-ca.pub"
    path="/etc/ssh/sshd_config"
    # If not present in sshd_config, append the keyword pair
    grep -q -F "${keyword_pair}" "${path}" || printf "\n%s\n%s" "${comment}" "${keyword_pair}" >> "${path}"
    # Make readable
    chmod 444 "${path}"
    # Restart sshd. This does not disconnect existing connections.
    sudo /etc/init.d/ssh restart # if you have upstart or system v
    sudo systemd restart sshd # if you have systemd
    EOF
    ```

    ### SSH Client (ssh)
    Configure the ssh client to trust the hosts CA, and thus any certs it signs. We'll use root to modify /etc/ssh.

    ```bash
    # Log into the CA computer.
    ssh you@ca

    # Create or update the client's /etc/ssh/ssh_known_hosts. By default, it doesn't exist.
    ssh root@client -p 22 bash <<\OUTER
    # set permissions
    chmod 774 /etc/ssh/ssh_known_hosts
    chmod 774 /etc/ssh/hosts-ca.pub
    # Allow the client to connect to servers from these domains
    tee -a /etc/ssh/ssh_known_hosts <<INNER
    # Added by configuration-manager@foo.com
    @cert-authority \*.domain1.com,\*.domain2.com $(cat /etc/ssh/hosts-ca.pub)
    INNER
    OUTER

    ```

    ### Sign an ssh server's public keys using hosts-ca
    ```bash
    # Log into the CA computer.
    ssh you@ca

    # For clarity, create a directory to hold the ssh server's public keys
    mkdir -p /usr/local/sshca/hosts/server

    # Download the public certs
    # Alternatively, ssh-keyscan works but would allow man-in-the-middle.
    scp -P 22 root@server:/etc/ssh/ssh_host_\{rsa_key.pub,dsa_key.pub,ecdsa_key.pub,ed25519_key.pub\} /usr/local/sshca/hosts/server/

    # Sign all of server's public keys, thus creating certificates with extension .pub
    sudo ssh-keygen -s /usr/local/sshca/hosts-ca -I "i am server" -h -n server,server.foo.com,192.168.0.1 -V +56w5d /usr/local/sshca/hosts/server/ssh_host_*.pub

    # Copy all server's newly signed certs back to server
    scp -P 22 /usr/local/sshca/hosts/server/ssh_host_*-cert.pub root@server:/etc/ssh/

    # Add the signed certs to sshd_config
    ssh root@server -p 22 bash <<\EOF
    comment="# Added by configuration-manager@foo.com"
    path="/etc/ssh/sshd_config"
    # Only add the keyword pair if it's not already there
    for part in rsa dsa ecdsa ed25519; do
    pubpath="/etc/ssh/ssh_host_${part}_key-cert.pub"
    keyword_pair="HostCertificate ${pubpath}"
    if [ -f "${pubpath}" ]; then
    grep -q -F "${keyword_pair}" "${path}" || printf "\n%s\n%s" "${comment}" "${keyword_pair}" >> "${path}"
    fi
    done
    # Restart sshd. This does not disconnect existing connections.
    sudo /etc/init.d/ssh restart # if you have upstart or system v
    sudo systemd restart sshd # if you have systemd
    EOF
    ```

    ### Sign an ssh client's public key using users-ca
    This assumes the user already has a keypair: id_rsa and id_rsa.pub.

    ```bash
    # Log into the CA computer.
    ssh you@ca

    # For clarity, create a directory to hold the ssh user's public keys
    mkdir -p /usr/local/sshca/users/user1

    # Download the user's public cert
    scp -P 22 user1@client:/home/user1/.ssh/id_rsa.pub /usr/local/sshca/users/user1/

    # Sign the user's public key, thus creating a certificate named id_rsa-cert.pub
    # Note: the user mentioned in the -n option must exist on the ssh server and allow logins
    sudo ssh-keygen -s /usr/local/sshca/users-ca -I "user1@foo.com" -n "user1" -V +52w \
    /usr/local/sshca/users/user1/id_rsa.pub

    # Optionally investigate the cert's details:
    ssh-keygen -Lf /usr/local/sshca/users/user1/id_rsa-cert.pub

    # Copy the signed certificate back to the user's .ssh directory
    scp -P 22 /usr/local/sshca/users/user1/id_rsa-cert.pub user1@client:/home/user1/.ssh/

    # Test from the ssh client.
    ssh user1@client
    ssh -vvv server # You should NOT be prompted. Troubleshoot otherwise. Use ssh-agent for any priv key passwords.
    ```

    ## Single-purpose Keys
    This allows you to create a certificate whose public key can only perform one task, like running /usr/local/scripts/myscript.sh. The intention here is for `user1` to run `sudo /usr/local/bin/myscript.sh`.

    ```bash
    # Log into the client
    ssh user1@client

    # Create a new keypair
    ssh-keygen -t rsa -b 4096 -C "user1@foo.com: single purpose key: sudo myscript.sh" -f /home/user1/.ssh/id_rsa-myscript

    # Try this key when connecting
    tee -a /home/user1/.ssh/config <<\EOF
    # Added by configuration-manager@foo.com"
    IdentityFile ~/.ssh/id_rsa-myscript
    EOF

    # Set required permissions. Details in man ssh_config:
    chmod 700 /home/user1/.ssh/config

    # Log into CA
    ssh user1@client

    # Set up a directory
    mkdir -p /usr/local/sshca/users/user1

    # Download the pub key
    scp -P 22 user1@client:/home/user1/.ssh/id_rsa-myscript.pub /usr/local/sshca/users/user1/

    # Sign it
    # NOTE: permit-pty helps troubleshooting (you can see error output) and avoids "PTY allocation request failed on channel 0".
    # NOTE: For details, see ForceCommand and permit-pty in man sshd_config
    sudo ssh-keygen -s /usr/local/sshca/users-ca -I "signed: user@foo.com: single purpose key: myscript.sh" \
    -n "user1" -V +52w -O clear -O permit-pty -O force-command="/usr/local/bin/myscript.sh" \
    /usr/local/sshca/users/user1/id_rsa-myscript.pub

    # Optionally inspect it
    ssh-keygen -Lf /usr/local/sshca/users/user1/id_rsa-myscript-cert.pub

    # Upload to client
    scp -P 22 /usr/local/sshca/users/user1/id_rsa-myscript-cert.pub user1@client:/home/user1/.ssh/


    # Test it
    ssh user1@client
    ssh server
    ```