Basicauth from external file (like htpasswd)?

1. Caddy version (caddy version): 2.4.1

2. How I run Caddy:

a. System environment:

Docker 20.10.7 on Ubuntu 18.04

b. Command:

docker-compose -f docker-compose.yml -f docker-compose.azurevm-highperf-caddy.yml up

c. Service/unit/compose file:

docker-compose.yml:

version: "2"

services:
  elasticsearch:
    build:
      context: elasticsearch/
    volumes:
      - elasticsearch-data:/usr/share/elasticsearch/data
      - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
    environment:
      node.name: elasticsearch
      cluster.initial_master_nodes: elasticsearch
      ES_CLUSTER_NAME: search-cluster
      ES_DATA_DIR: /usr/share/elasticsearch/data
    networks:
      - elk

volumes:
  elasticsearch-data:
    driver: local

networks:
  elk:
    driver: bridge

docker-compose.azurevm-highperf-caddy.yml:

version: "2"

services:
  elasticsearch:
    restart: always
    environment:
      ES_JAVA_OPTS: "-Xmx4000m -Xms4000m"

  caddy:
    image: caddy:2.4.1
    container_name: caddy
    restart: always
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy-config:/config
      - ./caddy-data:/data
    environment:
      - DOMAIN=adv-es-https-test-1.westeurope.cloudapp.azure.com
      - EMAIL=a@skwar.me
      - LOG_FILE=/data/access.log
    ports:
      - 80:80
      - 443:443
    networks:
      - elk
    depends_on:
      - elasticsearch

d. My complete Caddyfile or JSON config:

{$DOMAIN}:443

handle_path /elasticsearch* {
        basicauth bcrypt Elasticsearch {
                Bob JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
        }

        reverse_proxy http://elasticsearch:9200
}

3. The problem I’m having:

With the above configuration, changing/adding/removing usernames/passwords for basic auth would require a change of the Caddyfile and a restart or reload of caddy.

In nginx or Apache, the authentication data (usernames/passwords) is read from external htpasswd files. No restart/reload of server daemon is needed. It’s also easier to change the auth data by simply executing something along the lines of htpasswd -Bb /etc/nginx/htpasswd Secret "${password}"

Note: I’m not talking about adding htpasswd compatability. It’s fine if there’s a different tool or format. I’m talking about having the auth data (in whatever format) in an external file.

4. Error messages and/or full log output:

n/a

5. What I already tried:

n/a

6. Links to relevant resources:

n/a

There’s nothing built in to do that, for deliberate reasons. We try to avoid having configuration loaded from separate files. Keeps things isolated and repeatable.

You may use the import feature of the Caddyfile to pull the user/pass pairs from a separate file, but this still requires a config reload (which is zero-downtime, so there’s no issue there).

Or, you can look into using or writing a plugin to do what you need. See the Download Caddy page for a list of existing plugins (you might take a look at caddy-auth-portal)

1 Like

Works great!

I now have it like this:

handle_path /elasticsearch* {
        basicauth bcrypt Elasticsearch {
                import elasticsearch.auth
        }

        reverse_proxy http://elasticsearch:9200
}

It’s not as nice as htpasswd, though. htpasswd allows for easy UPDATING of passwords of a user. A simple printf "%s %s\n" "username" "$(caddy hash-password)" >> file.auth doesn’t cut it, as it would just add a line.

I guess some sort of sed or perl magic would be required here.

Or, instead of having ONE file with all the passwords, multiple files could be used, one per user, and then import elasticsearch.auth.*. In this case, removing a user would be as simple as rm elasticsearch.auth.username.

You can absolutely do that. import supports globs.

But anyways, basicauth is really just meant for simple usecases. It’s not meant to be a fully fledged authentication solution, cause that’s better solved by something else.

You might want to take a look at this plugin:

1 Like