Skip to content

Conversation

@eakman-datadog
Copy link

Overview

Support for META_PASSWORD_FILE as an alternative to META_PASSWORD. When set, META_PASSWORD_FILE should point to a file containing the password for the metadata engine. It should work exactly as META_PASSWORD does today, but just file oriented instead of environment variable oriented.

Currently, JuiceFS supports passing the metadata engine password via environment variable. In the context of Kubernetes, this typically means storing the password in a Kubernetes secret and then injecting into a pod via environment variable.

However many organizations discourage the use of Kubernetes secrets (due to lack of encryption, no native rotation capability, limited auditing, etc.) and instead use external secrets system such as Hashicorp Vault.

Moreover, some organizations use systems like consul-template, which only expose secrets as files.

The purpose of META_PASSWORD_FILE is expose the secret as a file to support systems that expose secrets as files instead of environment variables such as consul-template.

Testing

I used docker-compose to test this feature for both postgres and redis.

Postgres

docker-compose-postgres.yaml
# docker-compose-postgres.yaml
version: '3.8'

services:
  minio:
    image: minio/minio:latest
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      - MINIO_ROOT_USER=minioadmin
      - MINIO_ROOT_PASSWORD=minioadmin123
    command: server /data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - juicefs-test

  postgres:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=juicefs_test
      - POSTGRES_USER=juiceuser
      - POSTGRES_PASSWORD=postgresSecretPassword456
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U juiceuser -d juicefs_test"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - juicefs-test

  juicefs-test:
    build:
      context: ../../..  # Build from repo root
      dockerfile: scratch/meta-pass-file/e2e/Dockerfile
    depends_on:
      postgres:
        condition: service_healthy
      minio:
        condition: service_healthy
    volumes:
      - ./test-secrets:/secrets:ro
      - ./test-scripts:/scripts:ro
    environment:
      # MinIO/S3 credentials
      - AWS_ACCESS_KEY_ID=minioadmin
      - AWS_SECRET_ACCESS_KEY=minioadmin123
    networks:
      - juicefs-test
    working_dir: /root
    entrypoint: ["/bin/sh"]
    command: ["-c", "sleep infinity"]
    # Enable FUSE mounting
    privileged: true
    devices:
      - /dev/fuse:/dev/fuse
    cap_add:
      - SYS_ADMIN

networks:
  juicefs-test:
    driver: bridge

From the juicefs-test container.

Setup

export POSTGRES_URI="postgres://juiceuser@postgres:5432/juicefs_test?sslmode=disable"
export MINIO_ENDPOINT="http://minio:9000"
export BUCKET_NAME="juicefs-test-manual"

With META_PASSWORD_FILE set

~ # export META_PASSWORD_FILE=/secrets/postgres-password
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${POSTGRES_URI}" "manual-test-volume"
2025/10/29 20:53:38.291706 juicefs[30] <INFO>: Meta address: postgres://juiceuser:****@postgres:5432/juicefs_test?sslmode=disable [[email protected]:604]
2025/10/29 20:53:38.296369 juicefs[30] <INFO>: Data use s3://minio:9000/juicefs-test-manual/manual-test-volume/ [[email protected]:523]
2025/10/29 20:53:38.353088 juicefs[30] <INFO>: Volume is formatted as {
  "Name": "manual-test-volume",
  "UUID": "997696c3-f8f1-4bc3-8f38-22c1921db2c4",
  "Storage": "s3",
  "Bucket": "http://minio:9000/juicefs-test-manual",
  "AccessKey": "minioadmin",
  "SecretKey": "removed",
  "BlockSize": 4096,
  "Compression": "none",
  "EncryptAlgo": "aes256gcm-rsa",
  "KeyEncrypted": true,
  "TrashDays": 1,
  "MetaVersion": 1,
  "MinClientVersion": "1.1.0-A",
  "DirStats": true,
  "EnableACL": false
} [[email protected]:560]

Without anything set (fails)

~ # unset META_PASSWORD_FILE
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${POSTGRES_URI}" "manual-test-volume"
2025/10/29 20:53:57.530259 juicefs[41] <INFO>: Meta address: postgres://juiceuser@postgres:5432/juicefs_test?sslmode=disable [[email protected]:604]
2025/10/29 20:53:57.532487 juicefs[41] <FATAL>: Meta postgres://juiceuser@postgres:5432/juicefs_test?sslmode=disable is not available: ping database: failed to connect to `user=juiceuser database=juicefs_test`: 172.19.0.2:5432 (postgres): failed SASL auth: FATAL: password authentication failed for user "juiceuser" (SQLSTATE 28P01) [[email protected]:616]

With META_PASSWORD environment variable

~ # export META_PASSWORD=$(cat /secrets/postgres-password)
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${POSTGRES_URI}" "manual-test-volume"
2025/10/29 20:54:30.832111 juicefs[54] <INFO>: Meta address: postgres://juiceuser:****@postgres:5432/juicefs_test?sslmode=disable [[email protected]:604]
2025/10/29 20:54:30.837382 juicefs[54] <INFO>: Data use s3://minio:9000/juicefs-test-manual/manual-test-volume/ [[email protected]:523]
2025/10/29 20:54:30.869470 juicefs[54] <INFO>: Volume is formatted as {
  "Name": "manual-test-volume",
  "UUID": "997696c3-f8f1-4bc3-8f38-22c1921db2c4",
  "Storage": "s3",
  "Bucket": "http://minio:9000/juicefs-test-manual",
  "AccessKey": "minioadmin",
  "SecretKey": "removed",
  "BlockSize": 4096,
  "Compression": "none",
  "EncryptAlgo": "aes256gcm-rsa",
  "KeyEncrypted": true,
  "TrashDays": 1,
  "MetaVersion": 1,
  "MinClientVersion": "1.1.0-A",
  "DirStats": true,
  "EnableACL": false
} [[email protected]:560]

META_PASSWORD takes precedence over META_PASSWORD_FILE

~ # export META_PASSWORD="wrongpassword"
~ # export META_PASSWORD_FILE=/secrets/postgres-password
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${POSTGRES_URI}" "manual-test-volume"
2025/10/29 21:05:59.334016 juicefs[233] <INFO>: Meta address: postgres://juiceuser:****@postgres:5432/juicefs_test?sslmode=disable [[email protected]:604]
2025/10/29 21:05:59.336258 juicefs[233] <FATAL>: Meta postgres://juiceuser:****@postgres:5432/juicefs_test?sslmode=disable is not available: ping database: failed to connect to `user=juiceuser database=juicefs_test`: 172.19.0.2:5432 (postgres): failed SASL auth: FATAL: password authentication failed for user "juiceuser" (SQLSTATE 28P01) [[email protected]:616]
~ # unset META_PASSWORD
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${POSTGRES_URI}" "manual-test-volume"
2025/10/29 21:06:11.528819 juicefs[244] <INFO>: Meta address: postgres://juiceuser:****@postgres:5432/juicefs_test?sslmode=disable [[email protected]:604]
2025/10/29 21:06:11.533997 juicefs[244] <INFO>: Data use s3://minio:9000/juicefs-test-manual/manual-test-volume/ [[email protected]:523]
2025/10/29 21:06:11.567258 juicefs[244] <INFO>: Volume is formatted as {
  "Name": "manual-test-volume",
  "UUID": "02652bda-2770-493d-a9a5-c3ee9b7c8739",
  "Storage": "s3",
  "Bucket": "http://minio:9000/juicefs-test-manual",
  "AccessKey": "minioadmin",
  "SecretKey": "removed",
  "BlockSize": 4096,
  "Compression": "none",
  "EncryptAlgo": "aes256gcm-rsa",
  "KeyEncrypted": true,
  "TrashDays": 1,
  "MetaVersion": 1,
  "MinClientVersion": "1.1.0-A",
  "DirStats": true,
  "EnableACL": false
} [[email protected]:560]

Redis

docker-compose-redis.yaml
# docker-compose-redis.yaml
version: '3.8'

services:
  minio:
    image: minio/minio:latest
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      - MINIO_ROOT_USER=minioadmin
      - MINIO_ROOT_PASSWORD=minioadmin123
    command: server /data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - juicefs-test

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass redisSecretPassword123
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "redisSecretPassword123", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - juicefs-test

  juicefs-test:
    build:
      context: ../../..  # Build from repo root
      dockerfile: scratch/meta-pass-file/e2e/Dockerfile
    depends_on:
      redis:
        condition: service_healthy
      minio:
        condition: service_healthy
    volumes:
      - ./test-secrets:/secrets:ro
      - ./test-scripts:/scripts:ro
    environment:
      # MinIO/S3 credentials
      - AWS_ACCESS_KEY_ID=minioadmin
      - AWS_SECRET_ACCESS_KEY=minioadmin123
    networks:
      - juicefs-test
    working_dir: /root
    entrypoint: ["/bin/sh"]
    command: ["-c", "sleep infinity"]
    # Enable FUSE mounting
    privileged: true
    devices:
      - /dev/fuse:/dev/fuse
    cap_add:
      - SYS_ADMIN

networks:
  juicefs-test:
    driver: bridge

Setup

~ # export REDIS_URI="redis://redis:6379/1"
~ # export MINIO_ENDPOINT="http://minio:9000"
~ # export BUCKET_NAME="juicefs-test-redis"

With META_PASSWORD_FILE set

~ # export META_PASSWORD_FILE=/secrets/redis-password
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${REDIS_URI}" "redis-manual-test"
2025/10/29 21:10:27.197507 juicefs[14] <INFO>: Meta address: redis://redis:6379/1 [[email protected]:604]
2025/10/29 21:10:27.198968 juicefs[14] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly. [[email protected]:84]
2025/10/29 21:10:27.199072 juicefs[14] <INFO>: Ping redis latency: 62.125µs [[email protected]:3834]
2025/10/29 21:10:27.199448 juicefs[14] <INFO>: Data use s3://minio:9000/juicefs-test-redis/redis-manual-test/ [[email protected]:523]
2025/10/29 21:10:27.207012 juicefs[14] <INFO>: Volume is formatted as {
  "Name": "redis-manual-test",
  "UUID": "cea88bcb-4690-408b-86c8-08e43bb7d9bc",
  "Storage": "s3",
  "Bucket": "http://minio:9000/juicefs-test-redis",
  "AccessKey": "minioadmin",
  "SecretKey": "removed",
  "BlockSize": 4096,
  "Compression": "none",
  "EncryptAlgo": "aes256gcm-rsa",
  "KeyEncrypted": true,
  "TrashDays": 1,
  "MetaVersion": 1,
  "MinClientVersion": "1.1.0-A",
  "DirStats": true,
  "EnableACL": false
} [[email protected]:560]

With nothing set (fails)

~ # unset META_PASSWORD_FILE
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${REDIS_URI}" "redis-manual-test"
2025/10/29 21:10:46.934177 juicefs[26] <INFO>: Meta address: redis://redis:6379/1 [[email protected]:604]
2025/10/29 21:10:46.935114 juicefs[26] <WARNING>: parse info: NOAUTH Authentication required. [[email protected]:3809]
2025/10/29 21:10:46.935552 juicefs[26] <FATAL>: Load metadata: NOAUTH Authentication required. [[email protected]:505]

With META_PASSWORD set

~ # export META_PASSWORD="redisSecretPassword123"
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${REDIS_URI}" "redis-manual-test"
2025/10/29 21:11:02.732384 juicefs[38] <INFO>: Meta address: redis://redis:6379/1 [[email protected]:604]
2025/10/29 21:11:02.733231 juicefs[38] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly. [[email protected]:84]
2025/10/29 21:11:02.733319 juicefs[38] <INFO>: Ping redis latency: 58.959µs [[email protected]:3834]
2025/10/29 21:11:02.733651 juicefs[38] <INFO>: Data use s3://minio:9000/juicefs-test-redis/redis-manual-test/ [[email protected]:523]
2025/10/29 21:11:02.737574 juicefs[38] <INFO>: Volume is formatted as {
  "Name": "redis-manual-test",
  "UUID": "cea88bcb-4690-408b-86c8-08e43bb7d9bc",
  "Storage": "s3",
  "Bucket": "http://minio:9000/juicefs-test-redis",
  "AccessKey": "minioadmin",
  "SecretKey": "removed",
  "BlockSize": 4096,
  "Compression": "none",
  "EncryptAlgo": "aes256gcm-rsa",
  "KeyEncrypted": true,
  "TrashDays": 1,
  "MetaVersion": 1,
  "MinClientVersion": "1.1.0-A",
  "DirStats": true,
  "EnableACL": false
} [[email protected]:560]

META_PASSWORD takes precedence over META_PASSWORD_FILE

~ # export META_PASSWORD="wrongpassword"
~ # export META_PASSWORD_FILE=/secrets/redis-password
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${REDIS_URI}" "redis-manual-test"
2025/10/29 21:11:20.326208 juicefs[49] <INFO>: Meta address: redis://redis:6379/1 [[email protected]:604]
2025/10/29 21:11:20.327315 juicefs[49] <WARNING>: parse info: WRONGPASS invalid username-password pair or user is disabled. [[email protected]:3809]
2025/10/29 21:11:20.327744 juicefs[49] <FATAL>: Load metadata: WRONGPASS invalid username-password pair or user is disabled. [[email protected]:505]
~ # unset META_PASSWORD
~ # juicefs format --storage s3 --bucket ${MINIO_ENDPOINT}/${BUCKET_NAME} --access-key ${AWS_ACCESS_KEY_ID} --secret-key ${AWS_SECRET_ACCESS_KEY} "${REDIS_URI}" "redis-manual-test"
2025/10/29 21:11:34.111317 juicefs[60] <INFO>: Meta address: redis://redis:6379/1 [[email protected]:604]
2025/10/29 21:11:34.112528 juicefs[60] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly. [[email protected]:84]
2025/10/29 21:11:34.112609 juicefs[60] <INFO>: Ping redis latency: 51.708µs [[email protected]:3834]
2025/10/29 21:11:34.113014 juicefs[60] <INFO>: Data use s3://minio:9000/juicefs-test-redis/redis-manual-test/ [[email protected]:523]
2025/10/29 21:11:34.117048 juicefs[60] <INFO>: Volume is formatted as {
  "Name": "redis-manual-test",
  "UUID": "cea88bcb-4690-408b-86c8-08e43bb7d9bc",
  "Storage": "s3",
  "Bucket": "http://minio:9000/juicefs-test-redis",
  "AccessKey": "minioadmin",
  "SecretKey": "removed",
  "BlockSize": 4096,
  "Compression": "none",
  "EncryptAlgo": "aes256gcm-rsa",
  "KeyEncrypted": true,
  "TrashDays": 1,
  "MetaVersion": 1,
  "MinClientVersion": "1.1.0-A",
  "DirStats": true,
  "EnableACL": false
} [[email protected]:560]

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants