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 [NewClient@interface.go:604]
2025/10/29 20:53:38.296369 juicefs[30] <INFO>: Data use s3://minio:9000/juicefs-test-manual/manual-test-volume/ [format@format.go: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
} [format@format.go: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 [NewClient@interface.go: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) [NewClient@interface.go: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 [NewClient@interface.go:604]
2025/10/29 20:54:30.837382 juicefs[54] <INFO>: Data use s3://minio:9000/juicefs-test-manual/manual-test-volume/ [format@format.go: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
} [format@format.go: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 [NewClient@interface.go: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) [NewClient@interface.go: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 [NewClient@interface.go:604]
2025/10/29 21:06:11.533997 juicefs[244] <INFO>: Data use s3://minio:9000/juicefs-test-manual/manual-test-volume/ [format@format.go: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
} [format@format.go: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 [NewClient@interface.go: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. [checkRedisInfo@info.go:84]
2025/10/29 21:10:27.199072 juicefs[14] <INFO>: Ping redis latency: 62.125µs [checkServerConfig@redis.go:3834]
2025/10/29 21:10:27.199448 juicefs[14] <INFO>: Data use s3://minio:9000/juicefs-test-redis/redis-manual-test/ [format@format.go: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
} [format@format.go: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 [NewClient@interface.go:604]
2025/10/29 21:10:46.935114 juicefs[26] <WARNING>: parse info: NOAUTH Authentication required. [checkServerConfig@redis.go:3809]
2025/10/29 21:10:46.935552 juicefs[26] <FATAL>: Load metadata: NOAUTH Authentication required. [format@format.go: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 [NewClient@interface.go: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. [checkRedisInfo@info.go:84]
2025/10/29 21:11:02.733319 juicefs[38] <INFO>: Ping redis latency: 58.959µs [checkServerConfig@redis.go:3834]
2025/10/29 21:11:02.733651 juicefs[38] <INFO>: Data use s3://minio:9000/juicefs-test-redis/redis-manual-test/ [format@format.go: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
} [format@format.go: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 [NewClient@interface.go:604]
2025/10/29 21:11:20.327315 juicefs[49] <WARNING>: parse info: WRONGPASS invalid username-password pair or user is disabled. [checkServerConfig@redis.go:3809]
2025/10/29 21:11:20.327744 juicefs[49] <FATAL>: Load metadata: WRONGPASS invalid username-password pair or user is disabled. [format@format.go: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 [NewClient@interface.go: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. [checkRedisInfo@info.go:84]
2025/10/29 21:11:34.112609 juicefs[60] <INFO>: Ping redis latency: 51.708µs [checkServerConfig@redis.go:3834]
2025/10/29 21:11:34.113014 juicefs[60] <INFO>: Data use s3://minio:9000/juicefs-test-redis/redis-manual-test/ [format@format.go: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
} [format@format.go: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