Note |
---|
This feature is considered “at-risk” for removal as there are generally simpler ways to achieve the same results. If you use this feature, feel free to contact the project. |
File(s): conf/admin/general-admin.xml (V4,0), conf/admin/admin.properties (V4.1+) conf/admin/unlock-keys.xml, views/admin/unlock-keys.vm
Format: Native Spring, Velocity, Properties (V4.1+)
Table of Contents |
---|
Overview
The "attended restart" feature renders the IdP unusable if it restarts without human intervention. Most systems obviously focus on the opposite of that characteristic. The reason behind this feature is key protection. There aren't a lot of cost-effective, simple solutions to protecting private and secret keys (there are complex ones, expensive ones, and complex, expensive ones, of course). The concept behind this feature is that it allows keys to be encrypted on disk, but without the password stored anywhere with the key and entered manually when the service is restarted.
...
So my choice was to investigate what it would take to get the IdP to start with both the private and secret key(s) locked or unconfigured, and change that state at runtime. Somewhat surprisingly, this mostly worked.
Preconditions
This feature is a bit unusual so it's not just a "turn on setting" sort of thing, but something you have to make a few adjustments to the configuration to use. There are two parts to using this:
- Adjust the private and secret key settings to defer availability.
- Enable the unlock-keys webflow to get them installed after startup.
There are two significant risk points, the private key(s) used to sign messages and the secret key(s) used to support client-side session storage. Not every system uses the latter, but client-side storage is the default, so it's typically a factor. There are also private key(s) used to decrypt XML, but the impact of those keys is much less significant, and they don't get much use. Nevertheless, the feature supports unlocking private keys regardless of purpose so if you wanted to leave the decryption keys locked, that's certainly possible.
So how do you do it?
Credential Changes
Normally the configuration of keys and certificates for signing and encryption is found in conf/credentials.xml. To use this feature, it's necessary to move the critical beans defining these credentials out of this file and up into a globally visible place. The recommendation is to use conf/admin/unlock-keys.xml and move the bean(s) you want to "defer" to that file (with a couple of minor adjustments).
...
Enabling Module (V4.1+)
For V4.1+, configuring and using this feature requires that you first enable the "idp.admin.UnlockKeys" module if it isn't already enabled. Systems upgraded from older releases generally come pre-enabled due to the prior state of the configuration tree.
Code Block |
---|
(Windows)
C:\opt\shibboleth-idp> bin\module.bat -t idp.admin.UnlockKeys || bin\module.bat -e idp.admin.UnlockKeys
(Other)
$ bin/module.sh -t idp.admin.UnlockKeys || bin/module.sh -e idp.admin.UnlockKeys |
Preconditions
This feature is a bit unusual so it's not just a "turn on setting" sort of thing, but something you have to make a few adjustments to the configuration to use. There are two parts to using this:
Adjust the private and secret key settings to defer availability.
Enable the unlock-keys webflow to get them installed after startup.
There are two significant risk points, the private key(s) used to sign messages and the secret key(s) used to support client-side session storage. Not every system uses the latter, but client-side storage is the default, so it's typically a factor. There are also private key(s) used to decrypt XML, but the impact of those keys is much less significant, and they don't get much use. Nevertheless, the feature supports unlocking private keys regardless of purpose so if you wanted to leave the decryption keys locked, that's certainly possible.
So how do you do it?
Credential Changes
Normally the configuration of keys and certificates for signing and encryption is found in conf/credentials.xml. To use this feature, it's necessary to move the critical beans defining these credentials out of this file and up into a globally visible place. The recommendation is to use conf/admin/unlock-keys.xml and move the bean(s) you want to "defer" to that file (with a couple of minor adjustments).
The idea is to move the signing and/or encryption beans to this file, and then simply remove the lines referring to the private keys. You simply omit that part, and any such credential will initialize itself with only the certificate "half" in place, but no private key.
Examples are included below.
...
The secret key component, if it's in use, is normally configured in idp.properties, or in later versions, a separate credentials/secrets.properties file. The change needed here is simply to eliminate the passwords that unlock the keystore and key entry, normally these properties:
...
idp.properties
Code Block |
---|
idp.sealer.storePassword = password idp.sealer.keyPassword = password |
...
If the flow believes that it's done this successfully, it records that fact so that if it runs again it simply skips these steps. If it detects a failure, it leaves any remaining work undone and redisplays the form, and the log should usually indicate what didn't work. This is not meant as a fancy GUI for remote use without access to the server and the logs.
Localtabgroup | ||
---|---|---|
Localtab | active | true|
Expand | ||
| ||
To get this working, the flow has to be defined and enabled in conf/admin/general-admin.xml, and some Spring beans defined to describe to the flow what it needs to unlock. Enable the FlowThe following is added to (or uncommented in) the shibboleth.AvailableAdminFlows list bean: Code Block | | |
language | xml | title |
Code Block | ||
---|---|---|
| ||
<bean parent="shibboleth.OneTimeAdminFlow"
c:id="http://shibboleth.net/ns/profiles/unlock-keys"
p:loggingId="UnlockKeys"
p:authenticated="true"
p:policyName="AccessByAdminUser" /> |
The last couple of settings are deployment-specific. This example presumes that the rule for accessing the flow is that the user must login first, and that a map entry will be defined in conf/access-control.xml keyed under "AccessByAdminUser" that defines which usernames can access the flow. The access control features are described under AccessControlConfiguration.
There's total flexibility on this, it's up to you to define the rules. You can even set bean properties that typically are used in relying-party.xml like defaultAuthenticationMethods
to control what kind of authentication has to be done (e.g. requiring MFA). Authentication in general won't rely on the keys being unlocked here, so there won't usually be any circular dependency there.
Expand | ||
---|---|---|
| ||
To get this working, the module must be enabled (as mentioned above) and some Spring beans defined to describe to the flow what it needs to unlock. Controlling Access to the FlowThere are properties in conf/admin/admin.properties that will control the use of authentication and the access control rule applied to the flow. These are deployment-specific, but the defaults assume that the rule for accessing the flow is that the user must login first but grants no access. The idp.unlock.accessPolicy property can be set to "AccessByAdminUser" and a map entry defined in conf/access-control.xml keyed under "AccessByAdminUser" that defines which usernames can access the flow. These access control features are described under AccessControlConfiguration. You can even set bean properties that typically are used in relying-party.xml like If you want to customize this flow via XML or wish to apply settings not supported by properties, you can override the flow descriptor by creating your own bean (see the Flow Descriptor example in the Reference below. With this in place, you can add other properties to the bean (such as |
Configuring the Flow
The system reserves the file conf/admin/unlock-keys.xml for defining the beans necessary for the flow to run.
In addition to populating it with any "credential" beans whose private keys will be left out, this is where you define the information the flow needs so it knows what to do, using these beans:
shibboleth.unlock-keys.KeyStrategies
shibboleth.unlock-keys.Credentials
shibboleth.unlock-keys.PrivateKeys
All of these beans are ordered collections.
...
The template also illustrates a useful idea of embedding a SSO push link that can be used at the end to verify that the unlocked IdP works correctly (though you'd have to look at the log to know for certain the secret key is working).
Reference
Localtabgroup | ||||||
---|---|---|---|---|---|---|
Localtab | active | true|||||
Expand | ||||||
| ||||||
| Collection<DataSealerKeyStrategy> | Enumerates the key strategy beans used to supply secret key(s) to the IdP that should be unlocked by the flow | ||||
shibboleth.unlock-keys.Credentials | Collection<MutableCredential> | Enumerates the public key credentials that need to have an unlocked private key injected from the shibboleth.unlock-keys.PrivateKeys bean | ||||
shibboleth.unlock-keys.PrivateKeys | Collection<Resource> | Enumerates the resources containing private keys to unlock and inject into the credentials from the shibboleth.unlock-keys.Credentials bean | ||||
Localtab | ||||||
| ||||||
Localtab | ||||||
|
.unlock-keys.KeyStrategies | Enumerates the key strategy beans used to supply secret key(s) to the IdP that should be unlocked by the flow | |
shibboleth.unlock-keys.Credentials | Enumerates the public key credentials that need to have an unlocked private key injected from the shibboleth.unlock-keys.PrivateKeys bean | |
shibboleth.unlock-keys.PrivateKeys | Collection<Resource> | Enumerates the resources containing private keys to unlock and inject into the credentials from the shibboleth.unlock-keys.Credentials bean |
Expand | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||
The general properties configuring this flow via admin/admin.properties are:
|
Expand | |||||
---|---|---|---|---|---|
| |||||
To replace the internally defined flow descriptor bean, the following XML is required:
In older versions and upgraded systems, this list is defined in conf/admin/general-admin.xml. In V4.1+, no default version of the list is provided and it may simply be placed in conf/global.xml if needed. |
Example
In a typical example, the following assumes you want to unlock both the system-supplied secret keystore and the default signing key:
...
...
Example conf/admin/unlock-keys.xml
Code Block | ||
---|---|---|
| ||
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" default-init-method="initialize" default-destroy-method="destroy"> <!-- Attended restart unlock beans. --> <!-- Enumerate the system key strategy beans to unlock, typically just one. --> <util:list id="shibboleth.unlock-keys.KeyStrategies"> <ref bean="shibboleth.DataSealerKeyStrategy" /> </util:list> <!-- Enumerate credential bean refs and private key resources. --> <util:list id="shibboleth.unlock-keys.Credentials"> <ref bean="shibboleth.DefaultSigningCredential" /> </util:list> <util:list id="shibboleth.unlock-keys.PrivateKeys"> <bean class="org.springframework.core.io.FileSystemResource" c:_0="%{idp.signing.key}"/> </util:list> <bean id="shibboleth.DefaultSigningCredential" class="net.shibboleth.idp.profile.spring.factory.BasicX509CredentialFactoryBean" p:certificateResource="%{idp.signing.cert}" p:entityId="%{idp.entityID}" /> </beans> |
...