Skip to content

Commit a7c4bb8

Browse files
Add support for META_PASSWORD_FILE (#6438)
1 parent c586fb3 commit a7c4bb8

File tree

7 files changed

+345
-36
lines changed

7 files changed

+345
-36
lines changed

docs/en/administration/metadata/mysql_best_practices.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ export META_PASSWORD=mypassword
2121
juicefs mount -d "mysql://user:@(192.168.1.6:3306)/juicefs" /mnt/jfs
2222
```
2323

24+
Similarly, `META_PASSWORD_FILE` can be used to provide the database password as a file:
25+
26+
```shell
27+
export META_PASSWORD_FILE=/secret/mypassword.txt
28+
juicefs mount -d "mysql://user:@(192.168.1.6:3306)/juicefs" /mnt/jfs
29+
```
30+
2431
## Database connection control
2532

2633
MySQL is a multiple threads database, every client connection need a dedicate server thread, limition of total connections and new connects are prefered. JuiceFS now provides the following options for better control of the connections:

docs/en/administration/metadata/postgresql_best_practices.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ export META_PASSWORD=mypassword
2828
juicefs mount -d "postgres://[email protected]:5432/juicefs" /mnt/jfs
2929
```
3030

31-
## Database connection control
31+
Similarly, `META_PASSWORD_FILE` can be used to provide the database password as a file:
32+
33+
```shell
34+
export META_PASSWORD_FILE=/secret/mypassword.txt
35+
juicefs mount -d "postgres://[email protected]:5432/juicefs" /mnt/jfs
36+
```
3237

3338
PostgreSQL is a multiple process database, every client connection need a dedicate server process, limition of total connections and new connects are prefered. JuiceFS now provides the following options for better control of the connections:
3439

docs/en/reference/command_reference.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ juicefs format redis://localhost myjfs --storage=s3 --bucket=https://mybucket.s3
151151
juicefs format mysql://jfs:mypassword@(127.0.0.1:3306)/juicefs myjfs
152152
# A safer alternative
153153
META_PASSWORD=mypassword juicefs format mysql://jfs:@(127.0.0.1:3306)/juicefs myjfs
154+
# Provide password from file
155+
META_PASSWORD_FILE=/secret/mypassword.txt juicefs format mysql://jfs:@(127.0.0.1:3306)/juicefs myjfs
154156

155157
# Create a volume with quota enabled
156158
juicefs format sqlite3://myjfs.db myjfs --inodes=1000000 --capacity=102400

docs/en/reference/how_to_set_up_metadata_engine.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ For security purposes, it is recommended to pass the password using the environm
8383
export META_PASSWORD=mypassword
8484
```
8585

86+
Similarly, the password can be provided from a file using:
87+
88+
```shell
89+
export META_PASSWORD_FILE=/secret/mypassword.txt
90+
```
91+
8692
Then there is no need to set a password in the metadata URL.
8793

8894
```shell
@@ -108,6 +114,13 @@ export META_PASSWORD=mypassword
108114
juicefs mount -d "redis://192.168.1.6:6379/1" /mnt/jfs
109115
```
110116

117+
Similarly, the password can be provided from a file using as follows:
118+
119+
```shell
120+
export META_PASSWORD_FILE=/secret/mypassword.txt
121+
juicefs mount -d "redis://192.168.1.6:6379/1" /mnt/jfs
122+
```
123+
111124
#### Set up TLS
112125

113126
JuiceFS supports both TLS server-side encryption authentication and mTLS mutual encryption authentication connections to Redis. When connecting to Redis via TLS or mTLS, use the `rediss://` protocol header. However, when using TLS server-side encryption authentication, it is not necessary to specify the client certificate and private key.
@@ -503,6 +516,17 @@ juicefs format \
503516
pics
504517
```
505518

519+
Or equivalently:
520+
521+
```shell
522+
export META_PASSWORD_FILE="/secret/mypassword.txt"
523+
juicefs format \
524+
--storage s3 \
525+
... \
526+
"mysql://user@(192.168.1.6:3306)/juicefs" \
527+
pics
528+
```
529+
506530
To connect to a TLS enabled MySQL server, pass the `tls=true` parameter (or `tls=skip-verify` if using a self-signed certificate):
507531

508532
```shell
@@ -526,6 +550,13 @@ export META_PASSWORD="mypassword"
526550
juicefs mount -d "mysql://user@(192.168.1.6:3306)/juicefs" /mnt/jfs
527551
```
528552

553+
Passing the password using a file is also supported as follows:
554+
555+
```shell
556+
export META_PASSWORD_FILE="/secret/mypassword.txt"
557+
juicefs mount -d "mysql://user@(192.168.1.6:3306)/juicefs" /mnt/jfs
558+
```
559+
529560
To connect to a TLS enabled MySQL server, pass the `tls=true` parameter (or `tls=skip-verify` if using a self-signed certificate):
530561

531562
```shell
@@ -586,6 +617,17 @@ juicefs format \
586617
pics
587618
```
588619

620+
The password can also be passed using a file as follows:
621+
622+
```shell
623+
export META_PASSWORD_FILE="/secret/mypassword.txt"
624+
juicefs format \
625+
--storage s3 \
626+
... \
627+
"postgres://[email protected]:5432/juicefs" \
628+
pics
629+
```
630+
589631
:::note
590632

591633
1. JuiceFS uses public [schema](https://www.postgresql.org/docs/current/ddl-schemas.html) by default, if you want to use a `non-public schema`, you need to specify `search_path` in the connection string parameter. e.g `postgres://user:[email protected]:5432/juicefs?search_path=pguser1`
@@ -608,6 +650,13 @@ export META_PASSWORD="mypassword"
608650
juicefs mount -d "postgres://[email protected]:5432/juicefs" /mnt/jfs
609651
```
610652

653+
Passing a password using a file is also supported as follows:
654+
655+
```shell
656+
export META_PASSWORD_FILE="/secret/mypassword.txt"
657+
juicefs mount -d "postgres://[email protected]:5432/juicefs" /mnt/jfs
658+
```
659+
611660
#### Troubleshooting
612661

613662
The JuiceFS client connects to PostgreSQL via SSL encryption by default. If you encountered an error saying `pq: SSL is not enabled on the server`, you need to enable SSL encryption for PostgreSQL according to your own business scenario, or you can disable it by adding a parameter to the metadata URL Validation.

pkg/meta/interface.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ func Register(name string, register Creator) {
539539
metaDrivers[name] = register
540540
}
541541

542-
func setPasswordFromEnv(uri string) (string, error) {
542+
func injectPasswordIntoURI(uri, password string) (string, error) {
543543
atIndex := strings.LastIndex(uri, "@")
544544
if atIndex == -1 {
545545
return "", fmt.Errorf("invalid uri: %s", uri)
@@ -554,10 +554,37 @@ func setPasswordFromEnv(uri string) (string, error) {
554554
if len(s) == 2 && s[1] != "" {
555555
return uri, nil
556556
}
557-
pwd := url.UserPassword("", os.Getenv("META_PASSWORD")) // escape only password
557+
pwd := url.UserPassword("", password) // escape only password
558558
return uri[:dIndex] + s[0] + pwd.String() + uri[atIndex:], nil
559559
}
560560

561+
func readPasswordFromFile(filePath string) (string, error) {
562+
content, err := os.ReadFile(filePath)
563+
if err != nil {
564+
return "", fmt.Errorf("failed to read password file %s: %w", filePath, err)
565+
}
566+
return strings.TrimSpace(string(content)), nil
567+
}
568+
569+
func setPasswordFromEnv(uri string) (string, error) {
570+
var password string
571+
var err error
572+
573+
if metaPassword := os.Getenv("META_PASSWORD"); metaPassword != "" {
574+
password = metaPassword
575+
} else if passwordFile := os.Getenv("META_PASSWORD_FILE"); passwordFile != "" {
576+
password, err = readPasswordFromFile(passwordFile)
577+
if err != nil {
578+
return "", err
579+
}
580+
} else {
581+
// No password source available, return original URI
582+
return uri, nil
583+
}
584+
585+
return injectPasswordIntoURI(uri, password)
586+
}
587+
561588
// NewClient creates a Meta client for given uri.
562589
func NewClient(uri string, conf *Config) Meta {
563590
var err error
@@ -569,7 +596,7 @@ func NewClient(uri string, conf *Config) Meta {
569596
logger.Fatalf("invalid uri: %s", uri)
570597
}
571598
driver := uri[:p]
572-
if os.Getenv("META_PASSWORD") != "" && (driver == "mysql" || driver == "postgres") {
599+
if driver == "mysql" || driver == "postgres" {
573600
if uri, err = setPasswordFromEnv(uri); err != nil {
574601
logger.Fatalf(err.Error())
575602
}

0 commit comments

Comments
 (0)