Date: Fri, 29 Mar 2024 09:43:40 +0000 (UTC) Message-ID: <463453347.11.1711705420418@1dadf4e77608> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_10_1300720367.1711705420417" ------=_Part_10_1300720367.1711705420417 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
This feature is available in V3.4 and later of the software.
Current File(s): conf/admin/general-admin.xml, conf=
/admin/unlock-keys.xml, views/admin/unlock-keys.vm
Format: Native Spring, Velocity
V3.4 introduces a feature called "attended restart", which means that by= design the IdP is designed to be unusable if it restarts without human int= ervention. Most systems obviously focus on the opposite of that characteris= tic. The reason behind this feature is key protection. There aren't a lot o= f cost-effective, simple solutions to protecting private and secret keys (t= here are complex ones, expensive ones, and complex, expensive ones, of cour= se). 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.
An issue with the IdP is that it is a huge focal point for risk, and the= way that SAML is typically used focuses on deployability and not on securi= ty, namely the use of a pushed, signed token through the client whose only = security rests on the protection of the signing key. With no back-channel s= tep to add additional hurdles for an attacker, everything depends on the ke= y.
If all SPs ran Shibboleth or SimpleSAML.php, this would be a reasonable = thing to deal with by simply rotating the signing key through metadata on a= semi-regular basis. Unfortunately virtually nothing else out there has any= story for handling either key revocation or rotation, and if your auditors= find out about this, you may be facing some difficult conversations that s= tart with questions like how many administrators of your backup systems hav= e access to the private key.
My (Scott's) solution to this problem was to check out how much Amazon's= HMS solution costs, vomit, and then start looking into options. One of the= m would be some kind of "vault" solution to house the key, but that ultimat= ely just moves the problem and potentially adds a different set of staff wi= th access to the key. One of the things I thought about was how many times = in the 20+ year history I've run an IdP that I had to rely on a node restar= ting without me asking it to, and the answer was zero. It also helps that I= don't care about Docker or other technologies that solve deployment proble= ms I don't have.
So my choice was to investigate what it would take to get the IdP to sta= rt with both the private and secret key(s) locked or unconfigured, and chan= ge that state at runtime. Somewhat surprisingly, this not only mostly worke= d anyway, but in fact the IdP was happy to start up with no private key and= just issue unsigned responses, which while harmless (and perhaps a nice te= sting feature), seemed a bit much, so that's also been locked down a bit.= p>
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 configura= tion to use. There are two parts to using this:
There are two significant risk points, the private key(s) used to sign m= essages 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, s= o it's typically a factor. There are also private key(s) used to decrypt XM= L, but the impact of those keys is much less significant, and they don't ge= t much use. Nevertheless, the feature supports unlocking private keys regar= dless of purpose so if you wanted to leave the decryption keys locked, that= 's certainly possible.
So how do you do it?
Normally the configuration of keys and certificates for signing and encr= yption is found in conf/credentials.xml. To use this feature, it's= necessary to move the critical beans defining these credentials out of thi= s file and up into a globally visible place. The recommendation is to creat= e a file called conf/admin/unlock-keys.xml and move the bean(s) yo= u want to "defer" to that file (with a couple of minor adjustments).
You can copy all the Spring boilerplate from conf/global.xml and/or follow examples below, but 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 wil= l initialize itself with only the certificate "half" in place, but no priva= te key.
Examples are included below.
The secret key component, if it's in use, is normally configured in = idp.properties. The change needed here is simply to eliminate the pass= words that unlock the keystore and key entry, normally these properties:
idp.sea= ler.storePassword =3D password idp.sealer.keyPassword =3D password
If you remove these lines, or comment them out (prefix with a # characte= r), that automatically kicks the underlying secret key source into a "delay= ed init" mode that allows it to be unlocked at runtime.
So what happens if you do all this and then start the Java servlet conta= iner? By default, it's nothing really noticeable unless you try to login to= an SP. The lack of a secret key causes some loud warnings in the log any t= ime the software tries to load or store session data to the client, but it = doesn't actually cause a request to fail. The lack of a signing key, howeve= r, will cause SAML requests to terminate with an error because of the inabi= lity to sign messages. This is not ideal, but it's assumed that if you're u= sing this feature you're aware of what you're doing and you should know tha= t you need to unlock the system before putting it into use.
To use this feature, a new administr= ative flow is provided that has a crude user interface to collect passw= ord(s) via a web form and manipulate the system's internals to unlock and i= nstall the keys necessary to put the system into a normal state as if the f= eature hadn't been used. From that point on, the system should behave norma= lly until the next time it restarts. If the flow believes that it's done th= is successfully, it records that fact so that if it runs again it simply sk= ips these steps. If it detects a failure, it leaves any remaining work undo= ne and redisplays the form, and the log should usually indicate what didn't= work.
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.
The following is added to (or uncommented in) the shibboleth.Ava= ilableAdminFlows bean:
<bean= parent=3D"shibboleth.OneTimeAdminFlow" =09c:id=3D"http://shibboleth.net/ns/profiles/unlock-keys" p:loggingId=3D"UnlockKeys" =09p:authenticated=3D"true" =09p:policyName=3D"AccessByAdminUser" />
The last couple of properties are local. This example presumes that the = rule for accessing the flow is that the user must login first, and that a m= ap entry will be defined in conf/access-control.xml keyed under "A= ccessByAdminUser" that defines which usernames can access the flow. The acc= ess control features are described under = AccessControlConfiguration.
There's total flexibility on this, it's up to you to define the rules. Y=
ou can even set properties that typically are used in relying-party.xml=
like defaultAuthenticationMethods
to control what k=
ind of authentication has to be done (e.g. requiring MFA). Authentication i=
n general won't rely on the keys being unlocked here, so there won't usuall=
y be any circular dependency there.
It's possible to define everything necessary in global.xml, but= the system reserves the file conf/admin/unlock-keys.xml for doing= this and will load it if it's present.
In addition to populating it with any "credential" beans whose private k= eys will be left out, this is where you define the information the flow nee= ds so it knows what to do, using these beans:
All of these beans are ordered collections.
The KeyStrategies collection contains bean references to the DataSealer = key strategy objects that you're going to unlock. Typically this is just a = collection of one reference to shibboleth.DataSealerKeyStrategy, which is the name of the system bean that is included by default to = support the secret key features of the software. Unless you're doing someth= ing unusual and have created your own objects for some reason, that's all y= ou'd need to include. Of course, if you don't actually want to leave that k= eystore locked, you don't have to specify it.
The Credentials collection is where you enumerate the X509Credential bea= ns that you move out of conf/credentials.xml and from which you ch= op out the private key property.
The PrivateKeys collection is where you provide pointers to the private = keys to unlock and inject into the Credentials objects. These generally nee= d to be turned into explicit Spring FileSystemResource beans to avoid probl= ems with paths being misinterpreted as relative to the wrong location.
These two collections have to "line up" such that the position of the pr= ivate key in one list is meant for the Credential in the same position in t= he other list.
This is a fairly low tech feature; based on the collections here, you ma= y need to then modify the view template in views/admin/unlock-keys.vm and a= dd or remove sets of form fields with specific names to collect the passwor= ds you need. All of them are collected at once, and the template includes c= omments noting what you have to do. The flow defines the form fields "keyst= orePassword", "keyPassword", and "privateKeyPassword" to carry the password= s of each type, and multiple copies of the fields can be defined and should= be processed in order by the flow based on the order of the objects in the= collections described earlier.
You are expected to define the right number of fields and give them appr= opriate labels for your own use.
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 correctl= y (though you'd have to look at the log to know for certain the secret key = is working).
In a typical example, the following assumes you want to unlock both the = system-supplied secret keystore and the default signing key:
<?xml version=3D"1.0" encoding=3D"UTF-8"?> <beans xmlns=3D"http://www.springframework.org/schema/beans" xmlns:context=3D"http://www.springframework.org/schema/context" xmlns:util=3D"http://www.springframework.org/schema/util" xmlns:p=3D"ht= tp://www.springframework.org/schema/p" xmlns:c=3D"http://www.springframework.org/schema/c" xmlns:xsi=3D"http:/= /www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=3D"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://w= ww.springframework.org/schema/util/spring-util.xsd" default-init-method=3D"initialize" default-destroy-method=3D"destroy"> =20 <!-- Attended restart unlock beans. --> <!-- Enumerate the system key strategy beans to unlock, typically ju= st one. --> =20 <util:list id=3D"shibboleth.unlock-keys.KeyStrategies"> <ref bean=3D"shibboleth.DataSealerKeyStrategy" /> </util:list> =20 <!-- Enumerate credential bean refs and private key resources. -->= ; =20 <util:list id=3D"shibboleth.unlock-keys.Credentials"> <ref bean=3D"shibboleth.DefaultSigningCredential" /> </util:list> =20 <util:list id=3D"shibboleth.unlock-keys.PrivateKeys"> =09=09<bean class=3D"org.springframework.core.io.FileSystemResource" c:_0=3D"%{idp.signing.key}"/> </util:list> <bean id=3D"shibboleth.DefaultSigningCredential" class=3D"net.shibboleth.idp.profile.spring.factory.BasicX509Credent= ialFactoryBean" p:certificateResource=3D"%{idp.signing.cert}" p:entityId=3D"%{idp.entityID}" /> =20 </beans>
As you can see, mostly this is a lot of boilerplate, and some cut and pa= ste out of conf/credentials.xml that reuses the same properties ty= pically used to define the paths to the key and certificate, entityID, etc.= The use of a FileSystemResource class bean is usually required.
Because the existing signing Credential object is already assumed to be = named shibboleth.DefaultSigningCredential, transplanting t= hat with minor changes is possible. If you were defining additional keys yo= urself those names would be different.
If you were going to transplant the encryption/decryption key(s), you wo=
uld need to give them a bean name (via an id
attribute), =
move them here, and then reference them in the list in credentials.xml,=
via the <ref bean=3D"id"/>
syntax. In practice it'=
s probably not that necessary to worry about those keys as they're hardly e=
ver used, and much less critical to the security of the IdP.