web-dev-qa-db-ja.com

Dockerマシンの内外からIdentityServer4を使用するにはどうすればよいですか?

Dockerマシンの外部および内部から Identity Server (STS)に対して認証できるようにしたい。

コンテナーの内部と外部の両方で機能する正しい権限を設定するのに問題があります。権限を内部名mcoidentityserver:5000に設定すると、APIは認証できますが、クライアントがdockerネットワークの外部にあるため、クライアントはトークンを取得できません。権限を外部名localhost:5000に設定すると、クライアントはトークンを取得できますが、APIは権限名を認識しません(この場合のlocalhostはホストマシンであるため)。

権限を何に設定すればよいですか?または、おそらくdocker networkingを調整する必要がありますか?

赤い矢印は私が困っている部分です。 Three docker containers in a network, a client and PostgreSQL Admin, their ports and a red arrow showing where I think the problem lies.

細部

ASP.NET Core API(Linux)、Identity Server 4(Linux上のASP.NET Core)、PostgreSQLデータベースを使用するWindows 10 Docker開発環境をセットアップしています。 PostgreSQLは問題ではなく、完全を期すために図に含まれています。現時点では、ホスト上でPostgreSQLインスタンスを実行しているため、これは9876にマップされています。 mcoは、当社の略称です。

私は Identity Server 4の指示 に従って起動して実行しています。

コード

Visual Studioでの実行にのみ関連する実行コマンドがあるため、docker-compose.debug.ymlは含めていません。

docker-compose.yml

version: '2'

services:
mcodatabase:
    image: mcodatabase
    build:
    context: ./Data
    dockerfile: Dockerfile
    restart: always
    ports:
    - 9876:5432
    environment:
    POSTGRES_USER: mcodevuser
    POSTGRES_PASSWORD: password
    POSTGRES_DB: mcodev
    volumes:
    - postgresdata:/var/lib/postgresql/data
    networks:
    - mconetwork

mcoidentityserver:
    image: mcoidentityserver
    build:
    context: ./Mco.IdentityServer
    dockerfile: Dockerfile
    ports:
    - 5000:5000
    networks:
    - mconetwork

mcoapi:
    image: mcoapi
    build:
    context: ./Mco.Api
    dockerfile: Dockerfile
    ports:
    - 56107:80
    links:
    - mcodatabase
    depends_on:
    - "mcodatabase"
    - "mcoidentityserver"
    networks:
    - mconetwork

volumes:
postgresdata:

networks:
mconetwork:
    driver: bridge

docker-compose.override.yml

これは、追加の値を注入するためにVisual Studioプラグインによって作成されます。

version: '2'

services:
mcoapi:
    environment:
    - ASPNETCORE_ENVIRONMENT=Development
    ports:
    - "80" 

mcoidentityserver:
    environment:
    - ASPNETCORE_ENVIRONMENT=Development
    ports:
    - "5000" 

API Dockerfile

FROM Microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "Mco.Api.dll"]

Identity Server Dockerfile

FROM Microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
COPY ${source:-obj/Docker/publish} .
EXPOSE 5000
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["dotnet", "Mco.IdentityServer.dll"]

API Startup.cs

ここで、APIにIdentity Serverを使用して権限を設定するように指示します。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
    {
        // This can't work because we're running in docker and it doesn't understand what localhost:5000 is!
        Authority = "http://localhost:5000", 
        RequireHttpsMetadata = false,

        ApiName = "api1"
    });

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Identity Server Startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddIdentityServer()
            .AddTemporarySigningCredential()
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients());
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseIdentityServer();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    }
}

Identity Server Config.cs

public class Config
{
    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource("api1", "My API")
        };
    }

    public static IEnumerable<Client> GetClients()
    {
        return new List<Client>
        {
            new Client
            {
                ClientId = "client",

                // no interactive user, use the clientid/secret for authentication
                AllowedGrantTypes = GrantTypes.ClientCredentials,

                // secret for authentication
                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },

                // scopes that client has access to
                AllowedScopes = { "api1" }
            }
        };
    }
}

クライアント

コンソールアプリで実行する。

var discovery = DiscoveryClient.GetAsync("localhost:5000").Result;
var tokenClient = new TokenClient(discovery.TokenEndpoint, "client", "secret");
var tokenResponse = tokenClient.RequestClientCredentialsAsync("api1").Result;

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return 1;
}

var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);

var response = client.GetAsync("http://localhost:56107/test").Result;
if (!response.IsSuccessStatusCode)
{
    Console.WriteLine(response.StatusCode);
}
else
{
    var content = response.Content.ReadAsStringAsync().Result;
    Console.WriteLine(JArray.Parse(content));
}

前もって感謝します。

26
Dr Rob Lang

IssuerUriが明示的な定数に設定されていることを確認してください。 IP /ホスト名によるIdentity Serverインスタンスへのアクセスに関して同様の問題があり、次のように解決しました。

services.AddIdentityServer(x =>
{
    x.IssuerUri = "my_auth";
})

追伸典拠URLをhostname:5000に統合してみませんか?はい、Client[〜#〜] api [〜#〜]の両方が同じURLを呼び出すことが可能ですhostname:5000

  • 5000ポートが公開されています(問題ありません)
  • DNSは、Dockerコンテナー内で解決されます。
  • hostname:5000へのアクセス権があります(ファイアウォール、ネットワークトポロジなどを確認してください)

DNSは最もトリッキーな部分です。問題が発生した場合は、hostnameを解決するのではなく、公開されたIPでIdentity Serverにアクセスすることをお勧めします。

15
Ilya Chumakov

これを機能させるには、APIが許可されるように、IDサーバーインスタンスでdocker-compose.ymlとセットアップ [〜#〜] cors [〜#〜] の2つの環境変数を渡す必要がありました。それを呼び出す。 CORSの設定は、この質問の範囲外です。 この質問 で十分カバーできます。

Docker-Composeの変更

IDサーバーにはIDENTITY_ISSUERが必要です。これは、IDサーバーが自分に付ける名前です。この場合は、Docker HostのIPとIDサーバーのポートを使用しました。

  mcoidentityserver:
    image: mcoidentityserver
    build:
      context: ./Mco.IdentityServer
      dockerfile: Dockerfile
    environment:
      IDENTITY_ISSUER: "http://10.0.75.1:5000"
    ports:
       - 5000:5000
    networks:
     - mconetwork

APIは、権限がどこにあるかを知る必要があります。呼び出しはdockerネットワークの外に出る必要がないため、認証にdockerネットワーク名を使用できます。APIはIDサーバーを呼び出してトークンを確認するだけです。

  mcoapi:
    image: mcoapi
    build:
      context: ./Mco.Api
      dockerfile: Dockerfile
    environment:
      IDENTITY_AUTHORITY: "http://mcoidentityserver:5000"
    ports:
       - 56107:80
    links:
     - mcodatabase
     - mcoidentityserver
    depends_on:
     - "mcodatabase"
     - "mcoidentityserver"
    networks:
     - mconetwork

C#でこれらの値を使用する

Identity Server.cs

ConfigureServicesにIdentity Issuer名を設定します。

    public void ConfigureServices(IServiceCollection services)
    {
        var sqlConnectionString = Configuration.GetConnectionString("DefaultConnection");

        services
            .AddSingleton(Configuration)
            .AddMcoCore(sqlConnectionString)
            .AddIdentityServer(x => x.IssuerUri = Configuration["IDENTITY_ISSUER"])
            .AddTemporarySigningCredential()
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddCorsPolicyService<InMemoryCorsPolicyService>()
            .AddAspNetIdentity<User>();
    }

API Startup.cs

これで、Authorityを環境変数に設定できます。

app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
    {
        Authority = Configuration["IDENTITY_AUTHORITY"],
        RequireHttpsMetadata = false,
        ApiName = "api1"
    });

欠点

ここに示すように、ハードコードされたID発行者はローカルIPであるため、docker-composeは本番環境には適していません。代わりに、IDサーバーが実行されているdockerインスタンスにマップする適切なDNSエントリが必要です。これを行うには、docker-composeオーバーライドファイルを作成し、オーバーライドされた値でプロダクションをビルドします。

ilya-chumakov の協力に感謝します。

編集する

さらに、ブログに Linux docker + ASP.NET Core 2 + OAuth with Identity Server を構築するプロセス全体を記述しました。

8
Dr Rob Lang