Search code examples
c#.netkeycloaktestcontainersidentitymodel

Testcontainers keycloak error when run in gitlab pipeline


I am using Testcontainers to run some tests against keycloak. This works fine on my development machine but fails in gitlab pipeline.

The error I get is: Error connecting to http://docker:32769/realms/clienttest/.well-known/openid-configuration. HTTPS required. This error comes from the GetDiscoveryDocumentAsync extension method from the IdentityModel library which I use to get the bearer token for accessing the keycloak api. However HTTPS should not be required as the container is started with start-dev.

Creation of container

            new ContainerBuilder()
            .WithName("Keycloak-Client-Test-" + Guid.NewGuid().ToString("D"))
            .WithImage("quay.io/keycloak/keycloak:21.0.1")
            .WithPortBinding(privateKeycloakPort, true)
            .WithResourceMapping(new FileInfo("ContainerData/clienttest-realm.json"), new FileInfo("/opt/keycloak/data/import/realm.json"))
            .WithCommand("start-dev", "--import-realm")
            .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(r => r.ForPort(privateKeycloakPort)))
            .Build();

Test stage of pipeline

test:
  image: mcr.microsoft.com/dotnet/sdk:6.0
  stage: test
  services: 
    - name: docker:dind
      command: ["--tls=false"]
  variables:
    DOCKER_HOST: "tcp://docker:2375"
    DOCKER_TLS_CERTDIR: ""
    DOCKER_DRIVER: overlay2
  script:
    - dotnet test --logger:"junit;LogFilePath=UnitTestResult.xml"
  artifacts:
    paths:
      - "*/UnitTestResult.xml"
    reports:
      junit: "*/UnitTestResult.xml"

Solution

  • Turns out the error was given by IdentityModel because its default policy only allows http on loopback which worked for my development machine but not on a pipeline with docker in docker.

    I changed the GetDiscoveryDocumentAsync call from

        await loginClient.GetDiscoveryDocumentAsync(config.TokenIssuer);
    

    to

        await loginClient.GetDiscoveryDocumentAsync(
            new DiscoveryDocumentRequest
            {
                Address = config.TokenIssuer,
                Policy = new()
                {
                    RequireHttps = config.RequireHttps,
                    AllowHttpOnLoopback = true,
                }
            });
    

    Ofcourse the desired security level I pass in through the config so in production it stays secure and only in the tests is lowered.

    Note per dasniko's comment I changed the realm Require SSL setting to none before I found out the source of the problem was in IdentityModel. I strongly suspect this is also needed but have not verified it.