Running multiple instances of Identity server in docker cluster
The usual issue I've seen with clients is that they've put their AddDataProtection
registration before AddIdentityServer
.
AddIdentityServer
also calls AddDataProtection
with the default settings, which unfortunately will override whatever registrations you previously made.
So short answer: you need to put AddDataProtection
after AddIdentityServer
in your ConfigureServices
method.
I struggeled with this for days trying to implement a shared docker volume but it didn't work even when encrypting the keys witha certificate. So I ended up using the database -as suggested by @mackie.
Here is some code for inspiration:
X509Certificate2 cert = X509CertificateHelper.GetCertificateFromFile(options.Certificate.FilePath, options.Certificate.Passphrase); builder.AddSingleton<IXmlRepository, MongoXmlRepository>(); var sp = builder.BuildServiceProvider(); builder.AddSingleton<IXmlRepository, MongoXmlRepository>(); builder.AddDataProtection() .SetApplicationName(Assembly.GetExecutingAssembly().FullName) .AddKeyManagementOptions(o => { o.XmlRepository = sp.GetService<IXmlRepository>(); }) .ProtectKeysWithCertificate(cert) .SetDefaultKeyLifetime(TimeSpan.FromDays(options.LifeTimeInDays));
MongoXmlRepository is just a class implementing the IXmlRepository interface:
/// <summary>/// Implementation of the IXmlRepository, used by the DataProtection Service/// </summary>public class MongoXmlRepository : CrudRepository<MongoXElement, string>, IXmlRepository{ public MongoXmlRepository(ILoggerFactory loggerFactory, DatabaseRegistry databaseRegistry) : base(loggerFactory, databaseRegistry) { } public IReadOnlyCollection<XElement> GetAllElements() { try { var asyncCursor = this.Collection .Find(Builders<MongoXElement>.Filter.Empty); var entities = asyncCursor.ToList(); var xml = entities.Select(e => XElement.Parse(e.Xml)).ToList(); return xml; } catch (Exception e) { var errMessage = $"MongoXmlRepositoryError on {this.GetType()}:GetAllElements()"; this.Logger.LogError(errMessage, e); throw new RepositoryException(errMessage, e); } } public async void StoreElement(XElement element, string friendlyName) { var key = new MongoXElement { Xml = element.ToString(SaveOptions.DisableFormatting) }; await this.InsertAsync(key); }}
The implementation may differ depending on your store, in this case MongoDb was used.