diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8d4e906d142b84d14fd93b31ec0bcb074b980943..59308f2b480c26805a779983996e0c165de61923 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -51,6 +51,7 @@ jobs:
       - name: Run tests
         run: make testall
         env:
+          DEX_FOO_USER_PASSWORD: $2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy
           DEX_MYSQL_DATABASE: dex
           DEX_MYSQL_USER: root
           DEX_MYSQL_PASSWORD: root
diff --git a/cmd/dex/config.go b/cmd/dex/config.go
index 2519f6f5c0f3757d6e91a8d6d8bcd453713ead88..9db0ce3ff065f9e2eb2a785f88dcfc35bb21e219 100644
--- a/cmd/dex/config.go
+++ b/cmd/dex/config.go
@@ -85,10 +85,11 @@ type password storage.Password
 
 func (p *password) UnmarshalJSON(b []byte) error {
 	var data struct {
-		Email    string `json:"email"`
-		Username string `json:"username"`
-		UserID   string `json:"userID"`
-		Hash     string `json:"hash"`
+		Email       string `json:"email"`
+		Username    string `json:"username"`
+		UserID      string `json:"userID"`
+		Hash        string `json:"hash"`
+		HashFromEnv string `json:"hashFromEnv"`
 	}
 	if err := json.Unmarshal(b, &data); err != nil {
 		return err
@@ -98,6 +99,9 @@ func (p *password) UnmarshalJSON(b []byte) error {
 		Username: data.Username,
 		UserID:   data.UserID,
 	})
+	if len(data.Hash) == 0 && len(data.HashFromEnv) > 0 {
+		data.Hash = os.Getenv(data.HashFromEnv)
+	}
 	if len(data.Hash) == 0 {
 		return fmt.Errorf("no password hash provided")
 	}
diff --git a/cmd/dex/config_test.go b/cmd/dex/config_test.go
index 1df1f809456fa759719961392e0db6c733af1a8f..12c7b21884a14846e8fe4b555f8731dd184a26e2 100644
--- a/cmd/dex/config_test.go
+++ b/cmd/dex/config_test.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"os"
 	"testing"
 
 	"github.com/ghodss/yaml"
@@ -15,6 +16,8 @@ import (
 
 var _ = yaml.YAMLToJSON
 
+const testHashStaticPasswordEnv = "DEX_FOO_USER_PASSWORD"
+
 func TestValidConfiguration(t *testing.T) {
 	configuration := Config{
 		Issuer: "http://127.0.0.1:5556/dex",
@@ -212,3 +215,163 @@ logger:
 		t.Errorf("got!=want: %s", diff)
 	}
 }
+
+func TestUnmarshalConfigWithEnv(t *testing.T) {
+	staticPasswordEnv := os.Getenv(testHashStaticPasswordEnv)
+	if staticPasswordEnv == "" {
+		t.Skipf("test environment variable %q not set, skipping", testHashStaticPasswordEnv)
+	}
+	rawConfig := []byte(`
+issuer: http://127.0.0.1:5556/dex
+storage:
+  type: postgres
+  config:
+    host: 10.0.0.1
+    port: 65432
+    maxOpenConns: 5
+    maxIdleConns: 3
+    connMaxLifetime: 30
+    connectionTimeout: 3
+web:
+  http: 127.0.0.1:5556
+
+frontend:
+  dir: ./web
+  extra:
+    foo: bar
+
+staticClients:
+- id: example-app
+  redirectURIs:
+  - 'http://127.0.0.1:5555/callback'
+  name: 'Example App'
+  secret: ZXhhbXBsZS1hcHAtc2VjcmV0
+
+oauth2:
+  alwaysShowLoginScreen: true
+
+connectors:
+- type: mockCallback
+  id: mock
+  name: Example
+- type: oidc
+  id: google
+  name: Google
+  config:
+    issuer: https://accounts.google.com
+    clientID: foo
+    clientSecret: bar
+    redirectURI: http://127.0.0.1:5556/dex/callback/google
+
+enablePasswordDB: true
+staticPasswords:
+- email: "admin@example.com"
+  # bcrypt hash of the string "password"
+  hash: "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"
+  username: "admin"
+  userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
+- email: "foo@example.com"
+  hashFromEnv: "DEX_FOO_USER_PASSWORD"
+  username: "foo"
+  userID: "41331323-6f44-45e6-b3b9-2c4b60c02be5"
+
+expiry:
+  signingKeys: "7h"
+  idTokens: "25h"
+  authRequests: "25h"
+
+logger:
+  level: "debug"
+  format: "json"
+`)
+
+	want := Config{
+		Issuer: "http://127.0.0.1:5556/dex",
+		Storage: Storage{
+			Type: "postgres",
+			Config: &sql.Postgres{
+				NetworkDB: sql.NetworkDB{
+					Host:              "10.0.0.1",
+					Port:              65432,
+					MaxOpenConns:      5,
+					MaxIdleConns:      3,
+					ConnMaxLifetime:   30,
+					ConnectionTimeout: 3,
+				},
+			},
+		},
+		Web: Web{
+			HTTP: "127.0.0.1:5556",
+		},
+		Frontend: server.WebConfig{
+			Dir: "./web",
+			Extra: map[string]string{
+				"foo": "bar",
+			},
+		},
+		StaticClients: []storage.Client{
+			{
+				ID:     "example-app",
+				Secret: "ZXhhbXBsZS1hcHAtc2VjcmV0",
+				Name:   "Example App",
+				RedirectURIs: []string{
+					"http://127.0.0.1:5555/callback",
+				},
+			},
+		},
+		OAuth2: OAuth2{
+			AlwaysShowLoginScreen: true,
+		},
+		StaticConnectors: []Connector{
+			{
+				Type:   "mockCallback",
+				ID:     "mock",
+				Name:   "Example",
+				Config: &mock.CallbackConfig{},
+			},
+			{
+				Type: "oidc",
+				ID:   "google",
+				Name: "Google",
+				Config: &oidc.Config{
+					Issuer:       "https://accounts.google.com",
+					ClientID:     "foo",
+					ClientSecret: "bar",
+					RedirectURI:  "http://127.0.0.1:5556/dex/callback/google",
+				},
+			},
+		},
+		EnablePasswordDB: true,
+		StaticPasswords: []password{
+			{
+				Email:    "admin@example.com",
+				Hash:     []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
+				Username: "admin",
+				UserID:   "08a8684b-db88-4b73-90a9-3cd1661f5466",
+			},
+			{
+				Email:    "foo@example.com",
+				Hash:     []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
+				Username: "foo",
+				UserID:   "41331323-6f44-45e6-b3b9-2c4b60c02be5",
+			},
+		},
+		Expiry: Expiry{
+			SigningKeys:  "7h",
+			IDTokens:     "25h",
+			AuthRequests: "25h",
+		},
+		Logger: Logger{
+			Level:  "debug",
+			Format: "json",
+		},
+	}
+
+	var c Config
+	if err := yaml.Unmarshal(rawConfig, &c); err != nil {
+		t.Fatalf("failed to decode config: %v", err)
+	}
+	if diff := pretty.Compare(c, want); diff != "" {
+		t.Errorf("got!=want: %s", diff)
+	}
+}
diff --git a/storage/storage.go b/storage/storage.go
index cb2a7e0cdd368e7fea258b9c65fadc8c136ebe8b..42ecd8ed410a346ddf3913eb46f5d8ebe6419b75 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -292,6 +292,9 @@ type Password struct {
 	// Bcrypt encoded hash of the password. This package enforces a min cost value of 10
 	Hash []byte `json:"hash"`
 
+	// Bcrypt encoded hash of the password set in environment variable of this name.
+	HashFromEnv string `json:"hashFromEnv"`
+
 	// Optional username to display. NOT used during login.
 	Username string `json:"username"`