Skip to content

Update docker-compose to use https #634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
skoruba opened this issue Jun 20, 2020 · 18 comments
Closed

Update docker-compose to use https #634

skoruba opened this issue Jun 20, 2020 · 18 comments
Assignees
Labels
help wanted Extra attention is needed priority: high task Task

Comments

@skoruba
Copy link
Owner

skoruba commented Jun 20, 2020

It is necesarry to update in dev branch docker-compose for https scenario.

Good sample is provided from @bravecobra -
https://github.com/bravecobra/identityserver-ui

I would like to use http://127.0.0.1.xip.io - with https for development scenario as well - but currently it does not work properly on my machine - I need spend more time on this.

Currently this feature is blocker for next release, because I would like to provide support for docker as well and https is required.
Any help/PR is really welcome. 👍 🚀

Thanks

@skoruba skoruba added help wanted Extra attention is needed task Task priority: high labels Jun 20, 2020
@skoruba skoruba self-assigned this Jun 20, 2020
@ekjuanrejon
Copy link
Contributor

Why would you want to run https. I think a reverse proxy like ngix should be in front of the UI that will be using https

@ekjuanrejon
Copy link
Contributor

I think would be good if you make the feature configurable. I want to run the ui inside a kubernetes cluster using http and outside the kubernetes cluster to be access via https

@skoruba skoruba changed the title Update docker-compose to use https only Update docker-compose to use https Jun 21, 2020
@skoruba
Copy link
Owner Author

skoruba commented Jun 21, 2020

This is exactly what I want to achieve - configure ngnix for https scenario, ideally with xip.io, without modification host table. 😉 Your scenario will be definetely supported. Thanks for feedback.

@ekjuanrejon
Copy link
Contributor

ekjuanrejon commented Jun 22, 2020

Yes. I have done that. I currently use that setup for my local development. I have not use https for local development because I don't have such requirement but I suppose you can use a self-sign cert.

I am using traefik as a reverse proxy. https://docs.traefik.io/https/tls/ I have not used a self-sign cert. Below is my docker-compose

This way I don't have to be editing the host file. I currently use traefik.me which is similar to xip.io


services:
  traefik:
    image: "traefik:2.2.0"
    container_name: "traefik"
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.traefik.address=:9090"
    ports:
      - 80:80
      - 9090:9090
    restart: unless-stopped
    environment: 
      - AZURE_CLIENT_ID=${AZURE_CLIENT_ID}
      - AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET}
      - AZURE_RESOURCE_GROUP=${AZURE_RESOURCE_GROUP}
      - AZURE_SUBSCRIPTION_ID=${AZURE_SUBSCRIPTION_ID}
      - AZURE_TENANT_ID=${AZURE_TENANT_ID}
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
  
  skoruba.identityserver4.admin:
    image: skoruba-identityserver4-admin
    container_name: IdentityServer4Admin
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.identityserver4Admin.rule=Host(`idsrv4admin.traefik.me`)"
      - "traefik.http.routers.identityserver4Admin.entrypoints=web"
    command: dotnet Skoruba.IdentityServer4.Admin.dll /seed
    environment:
      - "ConnectionStrings__ConfigurationDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__PersistedGrantDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__IdentityDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__AdminLogDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__AdminAuditLogDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__DataProtectionDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "AdminConfiguration__IdentityAdminBaseUrl=http://idsrv4admin.traefik.me"
      - "AdminConfiguration__IdentityAdminRedirectUri=http://idsrv4admin.traefik.me/signin-oidc"
      - "AdminConfiguration__IdentityServerBaseUrl=http://login.traefik.me"
      - "AdminConfiguration__RequireHttpsMetadata=false"
      - "AdminConfiguration__PageTitle=SchoolGrades IdentityServer4 Admin"
    volumes:
      - "./shared/serilog.json:/app/serilog.json"
      - "./shared/identitydata.json:/app/identitydata.json"
      - "./shared/identityserverdata.json:/app/identityserverdata.json"
  
  skoruba.identityserver4.sts.identity:
    image: skoruba-identityserver4-sts-identity
    container_name: IdentityServer4
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.identityserver4STS.rule=Host(`login.traefik.me`)"
      - "traefik.http.routers.identityserver4STS.entrypoints=web"
    environment:
      - "ConnectionStrings__ConfigurationDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__PersistedGrantDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__IdentityDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__AdminLogDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__AdminAuditLogDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - "ConnectionStrings__DataProtectionDbConnection=Server=${SQL_HOST};Database=IdentityServer4Admin;User Id=${SQL_HOST_USER};Password=${SQL_HOST_PWD};MultipleActiveResultSets=true"
      - AdminConfiguration__PageTitle=SchoolGrades IdentityServer4
      - RegisterConfiguration__Enabled=False
    volumes:
      - "./shared/serilog.json:/app/serilog.json"
    networks:
      default:
        aliases:
          - login.traefik.me```

@bravecobra
Copy link
Contributor

Traefik will indeed solve the reverse proxy problem the same way nginx does. Just a different implementation.
The TLS support is a issue for which you will need a certificate somehow, either a really one like Let'sEncrypt or a self-signed one. I think the idea is to be able to verify the TLS support on a dev environment, nothing more. Which kind of cert you use is less relevant I guess. In my repo I tried to be as close to a production environment as possible and still offer a fully working solution exposing the difficulties of getting it to work.
xip.io will not solve the reverse dns fully. It's a shortcut, but you'll hit it quickly once you start with reverse proxies.

@ekjuanrejon
Copy link
Contributor

ekjuanrejon commented Jun 22, 2020

agreed. i have not tried using the self-signed cert. I am almost sure it will work and I will have https. My point is that the https should be the responsibility of nginx or traefik, not of the skoruba sts.

suppose i want to use Azure Application Gateway infront of skoruba sts

i stand to be correct. i am not a networking person

@bravecobra
Copy link
Contributor

True, in my solution the cert is part of nginx, not the sts.

@vpetkovic
Copy link

vpetkovic commented Jun 26, 2020

I think something along these lines could help and be a good start. Here's the explanation of each container:

  • nginx-proxy will route traffic to other containers by providing "VIRTUAL_HOST" environment variable.

  • letsencrypt-nginx-proxy-companion will auto-generate valid SSL cert for virtual host. (Using self-signed certs might add complexity and additional config of nginx)

  • nginx will run demo web server

     services:
         nginx-proxy:
             container_name: nginx-proxy
             ports:
                 - "80:80"
                 - "443:443"
             volumes:
                 - /etc/nginx/certs
                 - /etc/nginx/vhost.d
                 - /usr/share/nginx/html
                 - "/var/run/docker.sock:/tmp/docker.sock:ro"
             image: jwilder/nginx-proxy
         
         letsencrypt-nginx-proxy-companion:
             container_name: nginx-proxy-letsencrypt
             volumes:
                 - "/var/run/docker.sock:/var/run/docker.sock:ro"
             environment:
                 - DEFAULT_EMAIL=PUTYOUREMAILHERE
             image: jrcs/letsencrypt-nginx-proxy-companion
         
         nginx:
             container_name: nginx
             environment:
                 - VIRTUAL_HOST=127.0.0.1.xip.io
                 - LETSENCRYPT_HOST=127.0.0.1.xip.io
             image: nginx
    

This part is not directly related to https but it is related to nginx (some might've experienced it) as it might cause 502 bad gateway when authorizing a client. It is due the fact that nginx doesn't allow a large header content. To fix that nginx.conf needs to be modified and inlcude

    http{
        proxy_buffer_size   128k;
        proxy_buffers   4 256k;
        proxy_busy_buffers_size   256k;
        large_client_header_buffers 4 16k;
    }

@skoruba
Copy link
Owner Author

skoruba commented Jun 26, 2020

@vpetkovic - thanks for your suggestion and sample configuration, I will definitely test it. 👍🏼

@skoruba
Copy link
Owner Author

skoruba commented Jun 26, 2020

Unfortunatelly I got this error:

There were too many requests of a given type :: Error creating new order :: too many certificates already issued for: xip.io: see https://letsencrypt.org/docs/rate-limits/

@vpetkovic
Copy link

vpetkovic commented Jun 26, 2020

I am sorry I wasn't aware of such limitation when using xip.io with letsencrypt specifically, I used it with my own domain before to avoid dealing with self-signed certs and annoyances that come with it when trying to setup local environment for SSL as well as to have dev resemble prod env as close as possible.
So, it might still be a viable option for POC and pre-release scenarios if you own the domain.

I have not tested below (maybe i can do that over the weekend) but If to use self-signed certs instead of letsencrypt it could be as easy as getting rid of letsencrypt container then run the following to create self-signed certs using openSSL :

    cd /etc/nginx/certs
    sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/cert.key -out /etc/nginx/certs/cert.crt

Then modify default.conf in nginx container to point to self-signed certs created above.

    server {
        listen       80;
        listen       443 ssl;
        server_name  localhost;
        ssl_certificate /etc/nginx/certs/cert.crt;
        ssl_certificate_key /etc/nginx/certs/cert.key;
    }

Maybe additionally force http traffic to https:

    server {
        listen 80;
        return 301 https://$host$request_uri;
    }

    server {
        listen       443 ssl;
        server_name  localhost;
        ssl_certificate /etc/nginx/certs/cert.crt;
        ssl_certificate_key /etc/nginx/certs/cert.key;
    }

Not sure yet if any additional SSL config inside of default.conf is necessary.

@bravecobra
Copy link
Contributor

bravecobra commented Jun 27, 2020

That's why I used mkcert in my example to generate self signed certificates easily on any OS. The end-result is basically the same thing. Using Let's Encrypt will only work if either your endpoint is internet accessible on port 80 (which for most isn't the case) or the DNS resolves the challenge Let's Encrypt requires. If neither of those is available, Let's Encrypt won't work and you will need to resort to self-signed certificates. For dev purposes the latter is more than sufficient for testing.
I think this setup's attempt is to provide a solution that works for everybody in any given environment, thus I'd choose for self-signed ones as that works for everybody regardless of the environment. Making those certs should there for be easy, something that mkcert offers.
Of course you don't want to deploy that exact same solution with self-signed certificates to production. There you will need to use a real certificate or complete the Let's Encrypt setup.

@bravecobra
Copy link
Contributor

This part is not directly related to https but it is related to nginx (some might've experienced it) as it might cause 502 bad gateway when authorizing a client. It is due the fact that nginx doesn't allow a large header content. To fix that nginx.conf needs to be modified and inlcude

    http{
        proxy_buffer_size   128k;
        proxy_buffers   4 256k;
        proxy_busy_buffers_size   256k;
        large_client_header_buffers 4 16k;
    }

I increased the buffer in my setup as well.

@vpetkovic
Copy link

Sorry @skoruba , I haven't had a chance to look at this issue nor play around with self-signed certs as I originally imagined I would, but as you @bravecobra pointed out mkcert might be clean and easy way of dealing with it.
I have never used mkcert before and will be definitely add this to my arsenal as well, and hopefully this weekend will have a chance to spin those containers up and come up with a setup, now that I finally got all the parts for my new rig after a week without one lol

@DaleyKD
Copy link

DaleyKD commented Jul 8, 2020

I'm glad you guys seem to have a path for this. My local setup (Windows 10) uses https://github.com/nginx-proxy/nginx-proxy and all of my microservices are behind it: 4 "public" web sites, 1 IdentityServer4, 1 Skoruba IdentityServer.Admin, 1 gateway, and about 10 private services.

I wrote a .ps1 to do a lot of prep work to help with the setup. Things like download OpenSSL to generate a cert to save in the Windows Certificate Store and that same cert is used in the docker images, modify the etc/hosts file so I can setup https://acme.mydomain.local and https://identityserver.admin.mydomain.local, etc.

I was also able to split the project out into 3 docker-compose files (working toward 4 or 5).

There may have been easier ways of doing this... and it took a good couple weeks of me learning/implementing, but it seems to have made development easier for my team.

@skoruba
Copy link
Owner Author

skoruba commented Jul 8, 2020

@DaleyKD - can you share your setup please? Thanks

@bravecobra
Copy link
Contributor

@DaleyKD yeah, based on your description, I think my configuration is a bit easier, but with the same end result.

@skoruba
Copy link
Owner Author

skoruba commented Jul 18, 2020

Done - PR #657. Thanks for your help/suggestions.

@skoruba skoruba closed this as completed Jul 18, 2020
@skoruba skoruba mentioned this issue Jul 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed priority: high task Task
Projects
None yet
Development

No branches or pull requests

5 participants