3

My customer insists that IdentityServer4 should not be hosted entirely in DMZ for security reasons, especially considering that it has direct access to the database server.

From IdentityServer4 documentation and some other posts, it seems it should be possible to host MVC login pages in DMZ and leave IdentityServer4 API behind a firewall. If I understand correctly, I can achieve this using LoginUrl, LogoutUrl, ConsentUrl, ErrorUrl, DeviceVerificationUrl settings.

However, I'm not sure about the OpenID API. My SPA applications will need not only the login pages but also access to OpenID endpoints (connect/authorize, connect/userinfo, connect/checksession .well-known/openid-configuration).

How do I expose those IdentityServer4 endpoints in DMZ securely?

Currently I have no idea how those OpenID endpoints are created by IdentityServer4. In my app startup code, I just call AddIdentityServer and UseIdentityServer, and it does it's magic, registering the endpoints with my MVC app and then processing all the auth logic somewhere deep inside IdentityServer4.

Obviously, if I want to separate IdentityServer4 backend, I should call AddIdentityServer and UseIdentityServer in my backend API web service code, right? I can't use these method calls in my front-end website in DMZ because then IdentityServer4 will attempt to connect to the database for OpenID data, but the database is behind the firewall and unavailable directly from the DMZ.

I have the following typical code for IdentityServer4 initialization:

services.AddIdentityServer(
            options =>
            {
                ...
            })
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(Configuration.GetConnectionString("IdsvConnection"));
   ...
            })
            // this adds the operational data from DB (codes, tokens, consents)
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(Configuration.GetConnectionString("IdsvConnection"));
   ...
            })
            .AddAspNetIdentity<ApplicationUser>();

But if I leave this code in front-end, IdentityServer4 will not work. Is there some way to configure some other kind of operational and configuration store database access through backend API?

My current IdentityServer4 infrastructure looks like this:

SPA APP, 
mobile apps
     |
     |
MVC app 
with login pages 
and IdentityServer4 OpenID endpoint
     |
     |
SQL server 
with IdentityServer4 config 
and operational stores

but I need it like this:

SPA APP, 
mobile apps
     |
     |
--- DMZ ---
MVC app 
with login pages 
and IdentityServer4 OpenID endpoint
     |
     |
--- firewall ---
API web service                                
     |
     |
SQL server 
with IdentityServer4 config 
and operational stores
JustAMartin
  • 13,165
  • 18
  • 99
  • 183
  • there is no big difference between the oidc endpoints and mvc pages. if you would like to move all the db access behind the firewall, I could suggest to use microservices approach and fetch all the external resources through API. – d_f Jun 28 '19 at 09:10
  • @d_f it is specifically to IdentityServer4. Currently, I have written code for MVC login pages myself, based on some IdentityServer4 examples, so I have full control over it and I can configure IdentityServer4 to use the login pages through the URL settings I mentioned. But I have no control whatsoever over the openid endpoint of IdentityServer4 - I have no idea how do I separate it out into the same web app where my login pages are and don't break IdentityServer4, because I can't find any setting to tell IdentityServer4 to host connect/ and .well-known/ URLs outside of its internal API. – JustAMartin Jun 28 '19 at 09:46
  • can't get, what exactly you mean by "separating pages/endpoints into app". what I suggest seems to be a kind of such separation: you keep the oidc process where it is, but separate the data layer. I have experience of such separation and it works fine with no direct db access from within IdSrv. – d_f Jun 28 '19 at 09:57
  • @d_f - yes, my question is exactly about that - how do I separate the IdentityServer4 datalayer from its OpenID endpoints? How do I host IdentityServer4 datalayer in a separate .NET Core API web service? – JustAMartin Jun 28 '19 at 10:01
  • by default there's no huge data layer. for us it was easy to start with all "in memory" stores and implement whatever we needed. the main part is `IProfileService` where we rely on the custom `UserRepository` calling the API. – d_f Jun 28 '19 at 10:08
  • @d_f I updated my question with my current IdentityServer4 datalayer configuration setting. We are using SQL server as the storage. So, now the problem is that SQL server will not be available directly in DMZ. IdentityServer will have access to the server only if there is some way to tell it to use some kind of RemoteApiContext and proxy the DB accesses through that. I hoped IdentityServer has some built-in solution for such separation of its datalayer into API web service. – JustAMartin Jun 28 '19 at 10:16
  • I don't think such ready and open solution exists. That's enterprise, while the IdSrv is opensource. Sometimes we have to do something ourselves :) – d_f Jun 28 '19 at 10:49
  • Then I guess the easiest solution might be to add Idsrv at the back-end only, and then proxy the OpenID requests through my frontend app to Idsrv. It still might be tricky because Idsrv often relies upon cookies and I'll have to make sure I pass them through. Still, it might be easier than attempting to hack the ConfigurationStore and OperationalStore with custom implementations. – JustAMartin Jun 28 '19 at 11:04
  • That's not a hack, just implementation of open interfaces. The perfect feature in IdSrv is it's configurability. But anyway the final decision is yours. – d_f Jun 28 '19 at 11:50
  • @JustAMartin how you solve it finnaly – Ahmed Assaf Dec 17 '20 at 07:41
  • @d_f did you load all configuration in memory, and what happen with persistedGrants storage – Ahmed Assaf Dec 17 '20 at 07:42
  • @AhmedAssaf yes, we did, for all the static stuff. persistedGrants storage is dynamic by its nature, we used a custom storage in REDIS, just implemented the interface. – d_f Dec 17 '20 at 20:43
  • @d_f is there any source code available. – Ahmed Assaf Dec 22 '20 at 07:12

1 Answers1

1

A common requirement actually and not about coding. It is about ensuring that if DMZ is compromised the other layers are not. Standard solution is to use a reverse proxy in front of the Authorization Server (IdentityServer in your case). It ensures that UIs can still reach OAuth endpoints - but that if the DMZ infra is compromised the attacker cannot get their hands on the actual Authorixation Server and its database connections.

halfer
  • 19,824
  • 17
  • 99
  • 186
Gary Archer
  • 22,534
  • 2
  • 12
  • 24