> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minimus.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Keycloak FIPS Tutorial

> How to deploy Keycloak FIPS with a FIPS-approved keystore

To deploy Keycloak in FIPS mode, you need a FIPS-approved keystore. In this tutorial we will use the Bouncy Castle FIPS KeyStore (termed BCFKS). A BCFKS keystore is a Java KeyStore (JKS) format provided by Bouncy Castle that is specifically designed for FIPS-compliant cryptography.

The following guide involves the following components:

| **File**                        | **Purpose**                                    |
| ------------------------------- | ---------------------------------------------- |
| `server.keystore` (BCFKS)       | FIPS-approved keystore (private key + cert)    |
| `truststore.bcfks`              | FIPS-approved truststore (contains CA certs)   |
| `myCA.crt` / `myCA.key`         | Local CA (root) for signing/trusting dev certs |
| `keycloak.crt` / `keycloak.key` | Server certificate & key (PEM) for Keycloak    |

Prerequisites

* Docker available locally
* Token to pull images from the Minimus image registry
* A working directory for keystores and certs

## Deploy Keycloak for production

The following explains how to deploy Keycloak in either HTTPS mode or HTTP-dev mode.

<Steps>
  <Step title="Create a BCFKS Keystore (FIPS‑approved)">
    Use `keytool` from the Keycloak FIPS image to generate a BCFKS keystore and keypair (provider **CCJ**):

    ```bash Create BCFKS keystore expandable theme={null}
    docker run --rm \
      -v "$(pwd)":/tmp/keystore  \
      --entrypoint keytool  \
      reg.mini.dev/keycloak-fips \
      -J-Djava.security.properties=/usr/share/conf/java.security.append \
      -J-cp -J"/opt/keycloak/providers/*" \
      -v   -keystore /tmp/keystore/server.keystore \
      -storetype bcfks  \
      -providername CCJ \
      -alias "localhost" \
      -genkeypair  \
      -sigalg SHA512withRSA  \
      -keyalg RSA  \
      -dname CN="localhost" \
      -storepass "minimusstoretest2025"  \
      -keypass "minimusstorekeypass2025"
    ```

    If you encounter a permissions-related error, grant write permissions to your working directory and rerun the above command:

    <CodeGroup>
      ```bash Grant permissions theme={null}
      sudo chown 1000:1000 "$(pwd)"
      chmod 700 "$(pwd)"
      ```

      ```bash Permission denied error theme={null}
      keytool error: java.io.FileNotFoundException: /tmp/keystore/server.keystore (Permission denied)
      java.io.FileNotFoundException: /tmp/keystore/server.keystore (Permission denied)
      ```
    </CodeGroup>

    Verify the BCFKS keystore:

    <CodeGroup>
      ```bash Verify the keystore theme={null}
      docker run --rm -v "$(pwd)":/tmp/keystore  \
        --entrypoint keytool  \
        reg.mini.dev/keycloak-fips \
        -J-Djava.security.properties=/usr/share/conf/java.security.append \
        -J-cp -J"/opt/keycloak/providers/*"  \
        -v   -keystore /tmp/keystore/server.keystore  \
        -storetype bcfks \
        -list   -storepass "minimusstoretest2025"
      ```

      ```bash Sample output theme={null}
      Keystore type: BCFKS
      Keystore provider: CCJ

      Your keystore contains 1 entry

      Alias name: localhost
      Creation date: Dec 29, 2025
      Entry type: PrivateKeyEntry
      Certificate chain length: 1
      Certificate[1]:
      Owner: CN=localhost
      Issuer: CN=localhost
      Serial number: 7cd23b809f937152
      Valid from: Mon Dec 29 15:50:44 GMT 2025 until: Sun Mar 29 15:50:44 GMT 2026
      Certificate fingerprints:
               SHA1: 61:68:A4:62:D0:79:67:9F:35:A4:6A:E5:55:E6:FE:92:B7:22:21:1A
               SHA256: 66:BF:B2:98:97:BB:53:9F:27:1F:43:FB:C4:E3:5C:40:99:11:98:2B:79:A9:14:62:12:D8:8F:FE:1B:E9:57:7B
      Signature algorithm name: SHA512WITHRSA
      Subject Public Key Algorithm: 3072-bit RSA key
      Version: 3


      *******************************************
      ```
    </CodeGroup>
  </Step>

  <Step title=" Generate a Local CA and Server Certificate (PEM)">
    To set up HTTPS using PEM files (instead of a keystore), follow the steps to create a local CA and sign a server certificate.

    1. Generate a private key for the Certificate Authority (CA):
       ```bash theme={null}
       openssl genrsa -out myCA.key 4096
       # Saves the key to the output file myCA.key
       # Sets the key size to 4096 bits for extra security
       ```
    2. Create a root self-signed CA certificate:
       ```bash theme={null}
       openssl req -x509 -new -nodes -key myCA.key \
        -sha256 -days 3650 -out myCA.crt  \
        -subj "/C=US/ST=Local/L=Local/O=MyOrg/OU=Dev/CN=MyLocalCA"
       ```
    3. Generate a Server RSA private key for Keycloak:
       ```bash theme={null}
       openssl genrsa -out keycloak.key 2048
       # Saves the key to the output file keycloak.key
       # Sets the key size to 2048 bits for extra security
       ```
    4. CSR for your Keycloak host (edit CN):
       ```bash theme={null}
       openssl req -new -key keycloak.key \
         -out keycloak.csr   \
         -subj "/C=US/ST=Local/L=Local/O=MyOrg/OU=Dev/CN=keycloak.local"
       ```
    5. Create a file `keycloak.ext` containing certificate extension settings for a TLS certificate:
       ```bash theme={null}
       cat > keycloak.ext <<EOF
       authorityKeyIdentifier=keyid,issuer
       basicConstraints=CA:FALSE
       keyUsage = digitalSignature, keyEncipherment
       extendedKeyUsage = serverAuth
       subjectAltName = @alt_names
       [alt_names]
       DNS.1 = keycloak.local
       DNS.2 = localhost
       EOF
       ```
    6. Sign a Certificate Signing Request (CSR) with your CA:

    <CodeGroup>
      ```bash Sign CSR theme={null}
      openssl x509 -req -in keycloak.csr \
      -CA myCA.crt -CAkey myCA.key -CAcreateserial \
      -out keycloak.crt -days 825 -sha256 -extfile keycloak.ext
      ```

      ```bash Expected output theme={null}
      Certificate request self-signature ok
      subject=C=US, ST=Local, L=Local, O=MyOrg, OU=Dev, CN=keycloak.local
      ```
    </CodeGroup>

    7. Run `ls` to verify that the following certificates were created:
       * CA: `myCA.crt`, `myCA.key`, `myCA.srl`
       * Server (PEM): `keycloak.crt`, `keycloak.key`, `keycloak.csr`, `keycloak.ext`
  </Step>

  <Step title="Create a BCFKS Truststore (to trust your CA)">
    Import your CA into a BCFKS truststore:

    ```bash Import CA into truststore theme={null}
    docker run --rm -v "$(pwd)":/tmp/keystore \
      --entrypoint keytool  \
      reg.mini.dev/keycloak-fips \
      -J-Djava.security.properties=/usr/share/conf/java.security.append  \
      -J-cp -J"/opt/keycloak/providers/*"  \
      -v   -keystore /tmp/keystore/truststore.bcfks  \
      -storetype bcfks   -providername CCJ  \
      -import   -file /tmp/keystore/myCA.crt  \
      -storepass "minimusstoretest2025"   -trustcacerts   -noprompt
    ```
  </Step>

  <Step title="Run Keycloak">
    To run in dev mode, deploy Keycloak in HTTP:

    ```bash Run Keycloak in HTTP theme={null}
    docker run -d --rm -p 8080:8080 \
    -e KC_BOOTSTRAP_ADMIN_USERNAME=minimusadmin \
    -e KC_BOOTSTRAP_ADMIN_PASSWORD=minimusadminpass2025 \
    reg.mini.dev/keycloak-fips \
    start-dev --features=fips  --fips-mode=strict \
    --https-key-store-password='minimusstoretest2025' \
    --hostname=localhost   --log-level='INFO'
    ```

    Visit the Keycloak console (UI) at [http://localhost:8080](http://localhost:8080).

    <Info>
      Even in HTTP mode, FIPS checks still apply to admin and other passwords so ensure they have at least 14 characters.
    </Info>

    To run in production, deploy Keycloak with the truststore in HTTPS:

    ```bash Run Keycloak in HTTPS theme={null}
    docker run -d --rm -p 8443:8443 \
      -v "$(pwd)/keycloak.crt":/opt/keycloak/conf/tls.crt:ro \
      -v "$(pwd)/keycloak.key":/opt/keycloak/conf/tls.key:ro \
      -e KC_HTTPS_CERTIFICATE_FILE=/opt/keycloak/conf/tls.crt \
      -e KC_HTTPS_CERTIFICATE_KEY_FILE=/opt/keycloak/conf/tls.key \
      -e KC_BOOTSTRAP_ADMIN_USERNAME=minimusadmin2025 \
      -e KC_BOOTSTRAP_ADMIN_PASSWORD=minimusadmin2025 \
      reg.mini.dev/keycloak-fips \
      start  --features=fips       --fips-mode=strict  \
      --https-key-store-password='minimusstoretest2025'  \
      --hostname=localhost       --log-level='INFO'
    ```

    Visit the Keycloak console (UI) in HTTPS at [<u>https://localhost:8443</u>](https://localhost:8443).
  </Step>

  <Step title="Trust the CA locally (browser/curl)">
    ```bash theme={null}
    sudo cp myCA.crt /usr/local/share/ca-certificates/myCA.crt
    sudo update-ca-certificates
    ```
  </Step>

  <Step title="File hygiene">
    Change the file permissions in `server.keystore` so only the file owner has read/write access and nobody else has access:

    ```bash theme={null}
    chmod 600 *.key server.keystore *.bcfks || true
    ```
  </Step>
</Steps>

## Troubleshooting

If you get an error `password must be at least 112 bits`, it means that one or more passwords is under 14 characters long. Passwords should be 16-24 characters.

Check the passwords for the following variables: `KC_BOOTSTRAP_ADMIN_PASSWORD`, `KC_HTTPS_KEY_STORE_PASSWORD`, truststore password, etc.

***
