在docker cluster

时间:2018-04-06 07:22:17

标签: docker .net-core identityserver4

我的.net core 2.0应用程序基本上是Identity Server 4.当我只有一个实例时,它运行得很好。但是,如果我尝试运行更多身份服务器的一个实例,我就会遇到问题。

第一期

  

处理请求时发生未处理的异常。       CryptographicException:密钥环中找不到密钥{ec55dd66-7caf-4423-9dd6-74768e80675d}。   Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte [] protectedData,bool allowOperationsOnRevokedKeys,out UnprotectStatus status)

     

InvalidOperationException:无法解密防伪标记。       Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(string serializedToken)

我能够弄清楚这是因为密钥是在身份服务器的所有实例上生成的,而不是仅生成一个密钥,而且他们都使用了密钥。

我添加了以下代码。

services.AddDataProtection()
            .PersistKeysToFileSystem(new DirectoryInfo(settingsSetup.Settings.PersistKeysDirectory))
            .SetDefaultKeyLifetime(TimeSpan.FromDays(90))
            .SetApplicationName($"Awesome-IdentityServer-{_env.EnvironmentName}"); 

这基本上告诉身份服务器存储密钥的位置。我按照Persisting keys when hosting in a Docker container中的说明进行操作,因此我A folder that's a Docker volume that persists beyond the container's lifetime, such as a shared volume or a host-mounted volume.

Unforutnatlyly这个没有用,我现在得到以下错误

  

“idsrv未经过身份验证。失败消息:取消保护故障单”

我认为这意味着密钥需要以某种方式加密。

什么是Unprotect ticket failed,我该如何解决?我可以在docker节点中运行多个Identity Server实例吗?

现在加密。

services.AddDataProtection()
            .PersistKeysToFileSystem(new DirectoryInfo(settingsSetup.Settings.PersistKeysDirectory))
            .SetDefaultKeyLifetime(TimeSpan.FromDays(90))
            .ProtectKeysWithCertificate(LoadCertificate())
            .SetApplicationName($"Awesome-IdentityServer-{_env.EnvironmentName}");

身份服务器在日志中响应以下错误。

  

未配置XML加密器。密钥{2e0f629c-9dca-44fa-922e-5c5613bd27c8}可以持久保存,以未加密的形式存储。

用户显示此错误

  

CryptographicException:无法检索解密密钥。   System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData,string symmetricAlgorithmUri)

Authentication with Docker in ASP.NET Core也提到这应该有效。

我原本以为这是Identity Server 4的问题,因为他们的文档声明它是无状态的。我在GitHub上发布了一个问题Stateless or not Stateless与他们来回反复我倾向于认为这更像是一个码头问题然后是身份服务器问题。

2 个答案:

答案 0 :(得分:1)

我与客户见过的一个常见问题是,他们已在AddDataProtection之前进行AddIdentityServer注册。

AddIdentityServer也会使用默认设置调用AddDataProtection,不幸的是,这会覆盖您之前所做的任何注册。

如此简短的回答:您需要在AddDataProtection方法之后AddIdentityServer放置ConfigureServices

答案 1 :(得分:0)

我为此努力了几天,试图实现一个共享的docker卷,但是即使使用证书加密密钥,它也无法正常工作。因此,我最终使用了数据库-如 @mackie 所建议。

以下是一些启发代码:

 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 只是一个实现 IXmlRepository 接口的类:

/// <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);


    }
}

实施情况可能会因商店而异,在这种情况下,使用的是MongoDb。