Server Installation and Configuration Guide
Server Installation and Configuration Guide Red Hat Single Sign-On 7.6 For Use with Red Hat Single Sign-On 7.6 Red Hat Customer Content Services
./bin/jboss-cli.sh > .\bin\jboss-cli.bat patch apply <path-to-zip>/rh-sso-7.6.11-patch.zip subscription-manager repos --enable=jb-eap-7.4-for-rhel-<RHEL_VERSION>-server-rpms --enable=rhel-<RHEL_VERSION>-server-rpms subscription-manager repos --enable=jb-eap-7.4-for-rhel-8-x86_64-rpms --enable=rhel-8-for-x86_64-baseos-rpms --enable=rhel-8-for-x86_64-appstream-rpms subscription-manager repos --enable=rh-sso-7.6-for-rhel-<RHEL-VERSION>-server-rpms subscription-manager repos --enable=rh-sso-7.6-for-rhel-8-x86_64-rpms groupinstall rh-sso7 dnf groupinstall rh-sso7 .../bin/standalone.sh > ...\bin\standalone.bat ./bin/jboss-cli.sh --file=docs/examples/enable-elytron-se17.cli > .\bin\jboss-cli.bat --file=docs\examples\enable-elytron-se17.cli .../bin/standalone.sh --server-config=standalone-ha.xml > ...\bin\standalone.bat --server-config=standalone-ha.xml ./bin/jboss-cli.sh --file=docs/examples/enable-elytron-se17.cli -Dconfig=standalone-ha.xml > .\bin\jboss-cli.bat --file=docs\examples\enable-elytron-se17.cli "-Dconfig=standalone-ha.xml" <profiles> <profile name="auth-server-standalone"> </profile> <profile name="auth-server-clustered"> </profile> <socket-binding-groups> <socket-binding-group name="standard-sockets" default-interface="public"> </socket-binding-group> <socket-binding-group name="ha-sockets" default-interface="public"> </socket-binding-group> <!-- load-balancer-sockets should be removed in production systems and replaced with a better software or hardware based one --> <socket-binding-group name="load-balancer-sockets" default-interface="public"> </socket-binding-group> </socket-binding-groups> domain.sh -Djboss.http.port=80 <server-groups> <!-- load-balancer-group should be removed in production systems and replaced with a better software or hardware based one --> <server-group name="load-balancer-group" profile="load-balancer"> <jvm name="default"> <heap size="64m" max-size="512m"/> </jvm> <socket-binding-group ref="load-balancer-sockets"/> </server-group> <server-group name="auth-server-group" profile="auth-server-clustered"> <jvm name="default"> <heap size="64m" max-size="512m"/> </jvm> <socket-binding-group ref="ha-sockets"/> </server-group> </server-groups> <servers> <!-- remove or comment out next line --> <server name="load-balancer" group="loadbalancer-group"/> </servers> <servers> <server name="server-one" group="auth-server-group" auto-start="true"> <socket-bindings port-offset="150"/> </server> </servers> .../bin/domain.sh --host-config=host-master.xml > ...\bin\domain.bat --host-config=host-master.xml ./bin/jboss-cli.sh --file=docs/examples/enable-keycloak-se17-domain.cli > .\bin\jboss-cli.bat --file=docs\examples\enable-keycloak-se17-domain.cli add-user.sh What type of user do you wish to add? a) Management User (mgmt-users.properties) b) Application User (application-users.properties) (a): a Enter the details of the new user to add. Using realm 'ManagementRealm' as discovered from the existing property files. Username : admin Password recommendations are listed below. To modify these restrictions edit the add-user.properties configuration file. - The password should not be one of the following restricted values {root, admin, administrator} - The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s) - The password should be different from the username Password : Re-enter Password : What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[ ]: About to add user 'admin' for realm 'ManagementRealm' Is this correct yes/no? yes Added user 'admin' to file '/.../standalone/configuration/mgmt-users.properties' Added user 'admin' to file '/.../domain/configuration/mgmt-users.properties' Added user 'admin' with groups to file '/.../standalone/configuration/mgmt-groups.properties' Added user 'admin' with groups to file '/.../domain/configuration/mgmt-groups.properties' Is this new user going to be used for one AS process to connect to another AS process? e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls. yes/no? yes To represent the user add the following to the server-identities definition <secret value="bWdtdDEyMyE=" /> <management> <security-realms> <security-realm name="ManagementRealm"> <server-identities> <secret value="bWdtdDEyMyE="/> </server-identities> <remote security-realm="ManagementRealm" username="admin"> domain.sh --host-config=host-master.xml domain.sh --host-config=host-slave.xml <subsystem xmlns="urn:jboss:domain:keycloak-server:1.2"> <web-context>auth</web-context> </subsystem> <spi name="myspi"> <default-provider>myprovider</default-provider> <properties> <property name="spi-foo" value="spi-bar"/> </properties> <provider name="myprovider" enabled="true"> <properties> <property name="foo" value="bar"/> </properties> </provider> <provider name="mysecondprovider" enabled="true"> <properties> <property name="foo" value="foo"/> </properties> </provider> </spi> <spi name="user"> <properties> <property name="storageProviderTimeout" value="10000"/> </properties> </spi> <spi name="eventsStore"> <provider name="jpa" enabled="true"> <properties> <property name="exclude-events" value="[&quot;EVENT1&quot;, &quot;EVENT2&quot;]"/> </properties> </provider> </spi> .../bin/jboss-cli.sh > ...\bin\jboss-cli.bat [disconnected /] [disconnected /] connect connect [standalone@localhost:9990 /] [disconnected /] embed-server --server-config=standalone.xml [standalone@embedded /] .../bin/jboss-cli.sh --gui /subsystem=keycloak-server/theme=defaults/:write-attribute(name=cacheThemes,value=false) /subsystem=keycloak-server/theme=defaults/:write-attribute(name=cacheTemplates,value=false) .../bin/jboss-cli.sh --file=turn-off-caching.cli /subsystem=keycloak-server/:write-attribute(name=web-context,value=myContext) **/theme=defaults/:write-attribute(name=default,value=myTheme) **/spi=mySPI/:add **/spi=mySPI/provider=myProvider/:add(enabled=true) **/spi=mySPI/provider=myProvider/:write-attribute(name=enabled,value=false) **/spi=mySPI/:write-attribute(name=default-provider,value=myProvider) **/spi=mySPI/:map-put(name=properties, key=storageProviderTimeout, value=10000) **/spi=mySPI/:map-remove(name=properties, key=storageProviderTimeout) **/spi=dblock/:add(default-provider=jpa) **/spi=dblock/provider=jpa/:add(properties={lockWaitTimeout => "900"},enabled=true) **/spi=dblock/provider=jpa/:map-put(name=properties,key=lockWaitTimeout,value=3) **/spi=dblock/provider=jpa/:map-remove(name=properties,key=lockRecheckTime) **/spi=eventsStore/provider=jpa/:map-put(name=properties,key=exclude-events,value=[EVENT1,EVENT2]) bin/standalone.sh|bat -Dkeycloak.profile=preview profile=preview bin/standalone.sh|bat -Dkeycloak.profile.feature.<feature name>=enabled feature.docker=enabled bin/standalone.sh|bat -Dkeycloak.profile.feature.<feature name>=disabled feature.impersonation=disabled <?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.3" name="org.postgresql"> <resources> <resource-root path="postgresql-VERSION.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module> <subsystem xmlns="urn:jboss:domain:datasources:6.0"> <datasources> <drivers> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem> <subsystem xmlns="urn:jboss:domain:datasources:6.0"> <datasources> <drivers> <driver name="postgresql" module="org.postgresql"> <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class> </driver> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem> <subsystem xmlns="urn:jboss:domain:datasources:6.0"> <datasources> <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true"> <connection-url>jdbc:postgresql://localhost/keycloak</connection-url> <driver>postgresql</driver> <pool> <max-pool-size>20</max-pool-size> </pool> <security> <user-name>William</user-name> <password>password</password> </security> </datasource> </datasources> </subsystem> <subsystem xmlns="urn:jboss:domain:keycloak-server:1.2"> <spi name="connectionsJpa"> <provider name="default" enabled="true"> <properties> <property name="dataSource" value="java:jboss/datasources/KeycloakDS"/> <property name="initializeEmpty" value="false"/> <property name="migrationStrategy" value="manual"/> <property name="migrationExport" value="USD{jboss.home.dir}/keycloak-database-update.sql"/> </properties> </provider> </spi> </subsystem> show server_encoding; create database keycloak with encoding 'UTF8'; <spi name="hostname"> <default-provider>default</default-provider> <provider name="default" enabled="true"> <properties> <property name="frontendUrl" value="https://auth.example.com"/> <property name="forceBackendUrlToFrontendUrl" value="false"/> </properties> </provider> </spi> /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.frontendUrl,value="https://auth.example.com") standalone.sh -b 192.168.0.5 <interfaces> <interface name="management"> <inet-address value="USD{jboss.bind.address.management:127.0.0.1}"/> </interface> <interface name="public"> <inet-address value="USD{jboss.bind.address:127.0.0.1}"/> </interface> </interfaces> domain.sh -Djboss.bind.address=192.168.0.5 <socket-binding-group name="standard-sockets" default-interface="public" port-offset="USD{jboss.socket.binding.port-offset:0}"> <socket-binding name="management-http" interface="management" port="USD{jboss.management.http.port:9990}"/> <socket-binding name="management-https" interface="management" port="USD{jboss.management.https.port:9993}"/> <socket-binding name="ajp" port="USD{jboss.ajp.port:8009}"/> <socket-binding name="http" port="USD{jboss.http.port:8080}"/> <socket-binding name="https" port="USD{jboss.https.port:8443}"/> <socket-binding name="txn-recovery-environment" port="4712"/> <socket-binding name="txn-status-manager" port="4713"/> <outbound-socket-binding name="mail-smtp"> <remote-destination host="localhost" port="25"/> </outbound-socket-binding> </socket-binding-group> <server-groups> <server-group name="load-balancer-group" profile="load-balancer"> <socket-binding-group ref="load-balancer-sockets"/> </server-group> <server-group name="auth-server-group" profile="auth-server-clustered"> <socket-binding-group ref="ha-sockets"/> </server-group> </server-groups> keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 Enter keystore password: secret Re-enter new password: secret What is your first and last name? [Unknown]: localhost What is the name of your organizational unit? [Unknown]: Keycloak What is the name of your organization? [Unknown]: Red Hat What is the name of your City or Locality? [Unknown]: Westford What is the name of your State or Province? [Unknown]: MA What is the two-letter country code for this unit? [Unknown]: US Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? [no]: yes keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq -----BEGIN NEW CERTIFICATE REQUEST----- MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 29RvyeUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ 9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= -----END NEW CERTIFICATE REQUEST----- keytool -import -keystore keycloak.jks -file root.crt -alias root keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer Start batching commands batch /core-service=management/security-realm=UndertowRealm:add() /core-service=management/security-realm=UndertowRealm/server-identity=ssl:add(keystore-path=keycloak.jks, keystore-relative-to=jboss.server.config.dir, keystore-password=secret) /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=security-realm, value=UndertowRealm) Run the batch commands run-batch sh jboss-cli.sh --connect --file=sso_legacy.cli The batch executed successfully process-state: reload-required Start batching commands batch Add the keystore, key manager and ssl context configuration in the elytron subsystem /subsystem=elytron/key-store=httpsKS:add(relative-to=jboss.server.config.dir,path=keycloak.jks,credential-reference={clear-text=secret},type=JKS) /subsystem=elytron/key-manager=httpsKM:add(key-store=httpsKS,credential-reference={clear-text=secret}) /subsystem=elytron/server-ssl-context=httpsSSC:add(key-manager=httpsKM,protocols=["TLSv1.2"]) Change the undertow subsystem configuration to use the ssl context defined in the previous step for https /subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm) /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context, value=httpsSSC) Run the batch commands run-batch sh jboss-cli.sh --connect --file=sso.cli The batch executed successfully process-state: reload-required batch Add the keystore, key manager and ssl context configuration in the elytron subsystem /subsystem=elytron/key-store=httpsKS:add(relative-to=jboss.server.config.dir,path=keycloak.jks,credential-reference={clear-text=secret},type=JKS) /subsystem=elytron/key-manager=httpsKM:add(key-store=httpsKS,credential-reference={clear-text=secret}) /subsystem=elytron/server-ssl-context=httpsSSC:add(key-manager=httpsKM,protocols=["TLSv1.3"]) /subsystem=elytron/server-ssl-context=httpsSSC:write-attribute(name=cipher-suite-names,value=TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256) Change the undertow subsystem configuration to use the ssl context defined in the previous step for https /subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm) /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context, value=httpsSSC) Run the batch commands run-batch sh jboss-cli.sh --connect --file=sso.cli The batch executed successfully process-state: reload-required <spi name="connectionsHttpClient"> <provider name="default" enabled="true"> <properties> <property name="connection-pool-size" value="256"/> </properties> </provider> </spi> .*\.(google|googleapis)\.com;http://www-proxy.acme.com:8080 .*\.(google|googleapis)\.com;http://user01:pas2w0rd@www-proxy.acme.com:8080 All requests to Google APIs should use http://www-proxy.acme.com:8080 as proxy .*\.(google|googleapis)\.com;http://www-proxy.acme.com:8080 All requests to internal systems should use no proxy .*\.acme\.com;NO_PROXY All other requests should use http://fallback:8080 as proxy .*;http://fallback:8080 echo SETUP: Configure proxy routes for HttpClient SPI In case there is no connectionsHttpClient definition yet /subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:add(enabled=true) Configure the proxy-mappings /subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:write-attribute(name=properties.proxy-mappings,value=[".*\\.(google|googleapis)\\.com;http://www-proxy.acme.com:8080",".*\\.acme\\.com;NO_PROXY",".*;http://fallback:8080"]) <spi name="connectionsHttpClient"> <provider name="default" enabled="true"> <properties> <property name="proxy-mappings" value="[&quot;.*\\.(google|googleapis)\\.com;http://www-proxy.acme.com:8080&quot;,&quot;.*\\.acme\\.com;NO_PROXY&quot;,&quot;.*;http://fallback:8080&quot;]"/> </properties> </provider> </spi> HTTPS_PROXY=https://www-proxy.acme.com:8080 NO_PROXY=google.com,login.facebook.com <spi name="connectionsHttpClient"> <provider name="default" enabled="true"> <properties> <property name="proxy-mappings" value=".*;NO_PROXY"/> </properties> </provider> </spi> keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer <spi name="truststore"> <provider name="file" enabled="true"> <properties> <property name="file" value="path to your .jks file containing public certificates"/> <property name="password" value="password"/> <property name="hostname-verification-policy" value="WILDCARD"/> </properties> </provider> </spi> <subsystem xmlns="urn:jboss:domain:undertow:12.0"> <buffer-cache name="default"/> <server name="default-server"> <ajp-listener name="ajp" socket-binding="ajp"/> <http-listener name="default" socket-binding="http" redirect-socket="https" proxy-address-forwarding="true"/> </server> </subsystem> <subsystem xmlns="urn:jboss:domain:undertow:12.0"> <buffer-cache name="default"/> <server name="default-server"> <ajp-listener name="ajp" socket-binding="ajp"/> <http-listener name="default" socket-binding="http" redirect-socket="https"/> <host name="default-host" alias="localhost"> <filter-ref name="proxy-peer"/> </host> </server> <filters> <filter name="proxy-peer" class-name="io.undertow.server.handlers.ProxyPeerAddressHandler" module="io.undertow.core" /> </filters> </subsystem> <subsystem xmlns="urn:jboss:domain:undertow:12.0"> <http-listener name="default" socket-binding="http" proxy-address-forwarding="true" redirect-socket="proxy-https"/> </subsystem> <socket-binding-group name="standard-sockets" default-interface="public" port-offset="USD{jboss.socket.binding.port-offset:0}"> <socket-binding name="proxy-https" port="443"/> </socket-binding-group> 08:14:21,287 WARN XNIO-1 task-45 [org.keycloak.events] type=LOGIN_ERROR, realmId=master, clientId=security-admin-console, userId=8f20d7ba-4974-4811-a695-242c8fbd1bf8, ipAddress=X.X.X.X, error=invalid_user_credentials, auth_method=openid-connect, auth_type=code, redirect_uri=http://localhost:8080/auth/admin/master/console/?redirect_fragment=%2Frealms%2Fmaster%2Fevents-settings, code_id=a3d48b67-a439-4546-b992-e93311d6493e, username=admin <subsystem xmlns="urn:jboss:domain:undertow:12.0"> <handlers> <reverse-proxy name="lb-handler"> <host name="host1" outbound-socket-binding="remote-host1" scheme="ajp" path="/" instance-id="myroute1"/> <host name="host2" outbound-socket-binding="remote-host2" scheme="ajp" path="/" instance-id="myroute2"/> <host name="remote-host3" outbound-socket-binding="remote-host3" scheme="ajp" path="/" instance-id="myroute3"/> </reverse-proxy> </handlers> </subsystem> <socket-binding-group name="load-balancer-sockets" default-interface="public"> <outbound-socket-binding name="remote-host1"> <remote-destination host="localhost" port="8159"/> </outbound-socket-binding> <outbound-socket-binding name="remote-host2"> <remote-destination host="localhost" port="8259"/> </outbound-socket-binding> <outbound-socket-binding name="remote-host3"> <remote-destination host="192.168.0.5" port="8259"/> </outbound-socket-binding> </socket-binding-group> domain.sh --host-config=host-master.xml -Djboss.bind.address=192.168.0.2 -Djboss.bind.address.management=192.168.0.2 domain.sh --host-config=host-slave.xml -Djboss.bind.address=192.168.0.5 -Djboss.bind.address.management=192.168.0.5 -Djboss.domain.master.address=192.168.0.2 cd USDRHSSO_NODE1 ./standalone.sh -c standalone-ha.xml -Djboss.socket.binding.port-offset=100 -Djboss.node.name=node1 <subsystem xmlns="urn:jboss:domain:keycloak-server:1.2"> <spi name="stickySessionEncoder"> <provider name="infinispan" enabled="true"> <properties> <property name="shouldAttachRoute" value="false"/> </properties> </provider> </spi> </subsystem> <interfaces> <interface name="private"> <inet-address value="USD{jboss.bind.address.private:127.0.0.1}"/> </interface> </interfaces> <socket-binding-group name="standard-sockets" default-interface="public" port-offset="USD{jboss.socket.binding.port-offset:0}"> <socket-binding name="jgroups-mping" interface="private" port="0" multicast-address="USD{jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/> <socket-binding name="jgroups-tcp" interface="private" port="7600"/> <socket-binding name="jgroups-tcp-fd" interface="private" port="57600"/> <socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="USD{jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/> <socket-binding name="jgroups-udp-fd" interface="private" port="54200"/> <socket-binding name="modcluster" port="0" multicast-address="224.0.1.105" multicast-port="23364"/> </socket-binding-group> <spi name="dblock"> <provider name="jpa" enabled="true"> <properties> <property name="lockWaitTimeout" value="900"/> </properties> </provider> </spi> bin/standalone.sh --server-config=standalone-ha.xml bin/domain.sh --host-config=host-master.xml bin/domain.sh --host-config=host-slave.xml INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (Incoming-10,shared=udp) ISPN000094: Received new cluster view: [node1/keycloak|1] (2) [node1/keycloak, node2/keycloak] <subsystem xmlns="urn:jboss:domain:infinispan:12.0"> <cache-container name="keycloak"> <local-cache name="realms"> <object-memory size="10000"/> </local-cache> <local-cache name="users"> <object-memory size="10000"/> </local-cache> <local-cache name="keys"> <object-memory size="1000"/> <expiration max-idle="3600000"/> </local-cache> </cache-container> <subsystem xmlns="urn:jboss:domain:infinispan:12.0"> <cache-container name="keycloak"> <distributed-cache name="sessions" owners="2"/> <spi name="userCache"> <provider name="default" enabled="true"/> </spi> <spi name="realmCache"> <provider name="default" enabled="true"/> </spi> oc new-project <namespace> apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: rhsso-operator-group spec: targetNamespaces: - <namespace> # change this to the namespace you will use for RH-SSO --- apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: rhsso-operator spec: channel: stable installPlanApproval: Manual name: rhsso-operator source: redhat-operators sourceNamespace: openshift-marketplace # Here you can specify a specific Operator version, otherwise it will use the latest # startingCSV: rhsso-operator.7.6.0-opr-001 oc apply -f rhsso-operator-olm.yaml patch installplan USD(oc get ip -n <namespace> -o=jsonpath='{.items[?(@.spec.approved==false)].metadata.name}') -n <namespace> --type merge --patch '{"spec":{"approved":true}}' oc get pods NAME READY STATUS RESTARTS AGE rhsso-operator-558876f75c-m25mt 1/1 Running 0 28s apiVersion: keycloak.org/v1alpha1 kind: Keycloak metadata: name: example-sso labels: app: sso spec: instances: 1 externalAccess: enabled: True oc create -f sso.yaml -n sso keycloak.keycloak.org/example-sso created oc describe keycloak <CR-name> oc describe keycloak <CR-name> Name: example-keycloak Namespace: keycloak Labels: app=sso Annotations: <none> API Version: keycloak.org/v1alpha1 Kind: Keycloak Spec: External Access: Enabled: true Instances: 1 Status: Credential Secret: credential-example-keycloak Internal URL: https://<External URL to the deployed instance> Message: Phase: reconciling Ready: true Secondary Resources: Deployment: keycloak-postgresql Persistent Volume Claim: keycloak-postgresql-claim Prometheus Rule: keycloak Route: keycloak Secret: credential-example-keycloak keycloak-db-secret Service: keycloak-postgresql keycloak keycloak-discovery Service Monitor: keycloak Stateful Set: keycloak Version: Events: apiVersion: keycloak.org/v1alpha1 kind: KeycloakRealm metadata: name: test labels: app: sso spec: realm: id: "basic" realm: "basic" enabled: True displayName: "Basic Realm" instanceSelector: matchLabels: app: sso oc create -f initial_realm.yaml keycloak.keycloak.org/test created oc describe keycloak <CR-name> Name: example-keycloakrealm Namespace: keycloak Labels: app=sso Annotations: <none> API Version: keycloak.org/v1alpha1 Kind: KeycloakRealm Metadata: Creation Timestamp: 2019-12-03T09:46:02Z Finalizers: realm.cleanup Generation: 1 Resource Version: 804596 Self Link: /apis/keycloak.org/v1alpha1/namespaces/keycloak/keycloakrealms/example-keycloakrealm UID: b7b2f883-15b1-11ea-91e6-02cb885627a6 Spec: Instance Selector: Match Labels: App: sso Realm: Display Name: Basic Realm Enabled: true Id: basic Realm: basic Status: Login URL: Message: Phase: reconciling Ready: true Events: <none> apiVersion: keycloak.org/v1alpha1 kind: KeycloakClient metadata: name: example-client labels: app: sso spec: realmSelector: matchLabels: app: <matching labels for KeycloakRealm custom resource> client: # auto-generated if not supplied #id: 123 clientId: client-secret secret: client-secret # # other properties of Keycloak Client oc create -f initial_client.yaml keycloak.keycloak.org/example-client created apiVersion: v1 data: CLIENT_ID: <base64 encoded Client ID> CLIENT_SECRET: <base64 encoded Client Secret> kind: Secret oc describe keycloak <CR-name> Name: client-secret Namespace: keycloak Labels: app=sso API Version: keycloak.org/v1alpha1 Kind: KeycloakClient Spec: Client: Client Authenticator Type: client-secret Client Id: client-secret Id: keycloak-client-secret Realm Selector: Match Labels: App: sso Status: Message: Phase: reconciling Ready: true Secondary Resources: Secret: keycloak-client-secret-client-secret Events: <none> apiVersion: keycloak.org/v1alpha1 kind: KeycloakUser metadata: name: example-user spec: user: username: "realm_user" firstName: "John" lastName: "Doe" email: "user@example.com" enabled: True emailVerified: False credentials: - type: "password" value: "12345" realmRoles: - "offline_access" clientRoles: account: - "manage-account" realm-management: - "manage-users" realmSelector: matchLabels: app: sso oc create -f initial_user.yaml keycloak.keycloak.org/example-user created kind: Secret apiVersion: v1 data: password: <base64 encoded password> username: <base64 encoded username> type: Opaque oc describe keycloak <CR-name> Name: example-realm-user Namespace: keycloak Labels: app=sso API Version: keycloak.org/v1alpha1 Kind: KeycloakUser Spec: Realm Selector: Match Labels: App: sso User: Email: realm_user@redhat.com Credentials: Type: password Value: <user password> Email Verified: false Enabled: true First Name: John Last Name: Doe Username: realm_user Status: Message: Phase: reconciled Events: <none> apiVersion: v1 kind: Secret metadata: name: keycloak-db-secret namespace: keycloak stringData: POSTGRES_DATABASE: <Database Name> POSTGRES_EXTERNAL_ADDRESS: <External Database URL (resolvable by K8s)> POSTGRES_EXTERNAL_PORT: <External Database Port> POSTGRES_PASSWORD: <Database Password> # Required for AWS Backup functionality POSTGRES_SUPERUSER: "true" POSTGRES_USERNAME: <Database Username> SSLMODE: <TLS configuration for the Database connection> type: Opaque apiVersion: v1 kind: Secret metadata: name: keycloak-db-ssl-cert-secret namespace: keycloak type: Opaque data: root.crt: {root.crt base64} apiVersion: keycloak.org/v1alpha1 kind: Keycloak metadata: labels: app: sso name: example-keycloak namespace: keycloak spec: externalDatabase: enabled: true instances: 1 oc get secret keycloak-db-secret -o yaml apiVersion: v1 data POSTGRES_DATABASE: cm9vdA== POSTGRES_EXTERNAL_ADDRESS: MTcyLjE3LjAuMw== POSTGRES_EXTERNAL_PORT: NTQzMg== echo "MTcyLjE3LjAuMw==" | base64 -decode 192.0.2.3 oc get pods -o wide NAME READY STATUS RESTARTS AGE IP keycloak-0 1/1 Running 0 13m 192.0.2.0 keycloak-postgresql-c8vv27m 1/1 Running 0 24m 192.0.2.3 oc get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE keycloak ClusterIP 203.0.113.0 <none> 8443/TCP 27m keycloak-discovery ClusterIP None <none> 8080/TCP 27m keycloak-postgresql ClusterIP 203.0.113.1 <none> 5432/TCP 27m oc get endpoints keycloak-postgresql NAME ENDPOINTS AGE keycloak-postgresql 192.0.2.3.5432 27m oc get pods NAME READY STATUS RESTARTS AGE IP keycloak-0 1/1 Running 0 26m 192.0.2.0 keycloak-postgresql-c8vv27m 1/1 Running 0 36m 192.0.2.3 apiVersion: keycloak.org/v1alpha1 kind: Keycloak metadata: name: external-ref labels: app: external-sso spec: unmanaged: true external: enabled: true url: https://some.external.url apiVersion: v1 kind: Secret metadata: name: credential-external-ref type: Opaque data: ADMIN_USERNAME: YWRtaW4= ADMIN_PASSWORD: cGFzcw== apiVersion: keycloak.org/v1alpha1 kind: KeycloakRealm metadata: name: external-realm labels: app: external-sso spec: unmanaged: true realm: id: "basic" realm: "basic" instanceSelector: matchLabels: app: external-sso apiVersion: keycloak.org/v1alpha1 kind: KeycloakBackup metadata: name: test-backup oc create -f one-time-backup.yaml keycloak.keycloak.org/test-backup oc get pvc NAME STATUS VOLUME keycloak-backup-test-backup Bound pvc-e242-ew022d5-093q-3134n-41-adff keycloak-postresql-claim Bound pvc-e242-vs29202-9bcd7-093q-31-zadj oc get jobs NAME COMPLETIONS DURATION AGE test-backup 0/1 6s 6s oc get pods NAME READY STATUS RESTARTS AGE test-backup-5b4rf 0/1 Completed 0 24s keycloak-0 1/1 Running 0 52m keycloak-postgresql-c824c6-vv27m 1/1 Running 0 71m oc logs test-backup-5b4rf ==> Component data dump completed . . . . apiVersion: keycloak.org/v1alpha1 kind: Keycloak metadata: name: example-keycloak labels: app: sso spec: instances: 1 extensions: - <url_for_extension_or_theme> externalAccess: enabled: True oc edit test-realm apiVersion: keycloak.org/v1alpha1 kind: Keycloak metadata: name: example-keycloak labels: app: sso spec: instances: 2 migration: strategy: recreate backups: enabled: True externalAccess: enabled: True