ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / cmd/rotate-credential/main.go

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / cmd/rotate-credential/main.go
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive membercmd/rotate-credential/main.go
Original SHA-256b0931b197a6db5def2f983a367065246b095363b2b07b7766658b7cb01376a0d
Git blob SHAb6e954c5a8a504096d44ed7ac655f0a77ae906f3
Reading-copy SHA-256b0931b197a6db5def2f983a367065246b095363b2b07b7766658b7cb01376a0d

Original source ↗

Recovered source transcript

// Command rotate-credential sets a new password for an existing account through the SAME primitives the // login path uses: the versioned pepper, PBKDF2 HMAC SHA 256 at the configured iteration count, and the // auth_set_credential SECURITY DEFINER function. // // It exists because three credentials were written into docs/BUILD_STATE.md in plaintext and are therefore // burned. Rotating them by hand against the database would mean reimplementing the KDF, and a second // implementation of a KDF is a second thing that can be subtly wrong; going through the real primitives // means a rotated credential is byte for byte the shape a normal one has. // // Usage: // // rotate-credential -dsn <migrator dsn> -email <address> -password <new> package main import ( "context" "encoding/base64" "flag" "log" "os" "strconv" "strings" "github.com/jackc/pgx/v5/pgxpool" "github.com/missionworkforce/missionmatch/internal/platform/security" ) func main() { dsn := flag.String("dsn", "", "migrator DSN, defaults to MM_MIGRATOR_DATABASE_URL") email := flag.String("email", "", "account email") newPass := flag.String("password", "", "the replacement password") pepperEnv := flag.String("pepper", "", "credential pepper, server side only, defaults to MM_CREDENTIAL_PEPPER") flag.Parse() if *dsn == "" { *dsn = os.Getenv("MM_MIGRATOR_DATABASE_URL") } if *pepperEnv == "" { *pepperEnv = os.Getenv("MM_CREDENTIAL_PEPPER") } // THE PASSWORD MAY COME FROM THE ENVIRONMENT INSTEAD OF argv, and it should. // // argv is world readable through ps for as long as the process runs, so -password publishes the credential // to every account on the host. That is the same exposure found in mm-identity-sync earlier tonight, where // two migrator DSNs were passed as flags and measured as one visible exposure per run. A tool whose entire // purpose is to set a credential correctly should not leak it on the way in. // // The flag is kept, because it is in the recorded runbook and breaking it would be worse than the leak it // avoids, but MM_ROTATE_PASSWORD is now the preferred path and it is what the Gate C sweep uses. if *newPass == "" { *newPass = os.Getenv("MM_ROTATE_PASSWORD") } if *dsn == "" || strings.TrimSpace(*email) == "" || *newPass == "" { log.Fatal("rotate-credential: -dsn, -email, and a password from -password or MM_ROTATE_PASSWORD are required") } if *pepperEnv == "" { log.Fatal("rotate-credential: the credential pepper is required, or the hash would not match what login computes") } if len(*newPass) > 64 { log.Fatal("rotate-credential: password exceeds the 64 character cap the CAVP tested length bound imposes") } // The pepper is decoded exactly as config does it, base64 to 32 raw bytes. Decoding it any other way // here would produce a hash the login path cannot verify, and the failure would look like a wrong // password rather than a wrong tool. raw, err := base64.StdEncoding.DecodeString(strings.TrimSpace(*pepperEnv)) if err != nil { log.Fatalf("rotate-credential: the pepper is not valid base64: %v", err) } version := 1 if v := strings.TrimSpace(os.Getenv("MM_CREDENTIAL_PEPPER_VERSION")); v != "" { if n, cerr := strconv.Atoi(v); cerr == nil { version = n } } pepper, err := security.NewPepper(version, map[int][]byte{version: raw}) if err != nil { log.Fatalf("rotate-credential: pepper: %v", err) } hasher, err := security.NewHasher(pepper, security.PBKDF2Iterations) if err != nil { log.Fatalf("rotate-credential: hasher: %v", err) } encoded, ver, err := hasher.Hash(*newPass) if err != nil { log.Fatalf("rotate-credential: hash: %v", err) } ctx := context.Background() pool, err := pgxpool.New(ctx, *dsn) if err != nil { log.Fatalf("rotate-credential: pool: %v", err) } defer pool.Close() var uid, orgID, normalized string if err := pool.QueryRow(ctx, `SELECT id::text, organization_id::text, lower(email) FROM users WHERE lower(email)=lower($1)`, strings.TrimSpace(*email)).Scan(&uid, &orgID, &normalized); err != nil { log.Fatalf("rotate-credential: no such account %q: %v", *email, err) } if _, err := pool.Exec(ctx, `SELECT auth_set_credential($1,$2,$3,$4,$5)`, uid, orgID, normalized, encoded, ver); err != nil { log.Fatalf("rotate-credential: set credential: %v", err) } // The new secret is NEVER printed. Whoever ran this already has it; echoing it would put it in a shell // history and a terminal scrollback, which is how the original problem started. log.Printf("rotate-credential: rotated %s, pepper version %d, iterations %d", normalized, ver, security.PBKDF2Iterations) }

Search equations, builds, manuscript text, and recovered sources.