Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow multiple private keys but use the latest one #1748

Open
wants to merge 67 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
43b1440
key manager
h2zh Oct 29, 2024
5f4532f
check private keys dir every 10 mins
h2zh Oct 30, 2024
da110ab
Use the latest private key
h2zh Oct 31, 2024
3fc8d52
enbale concurrent access to the issuer private keys in memory, by ado…
h2zh Nov 1, 2024
46380ef
Checks the directory containing .pem files every 5 minutes and loads …
h2zh Nov 4, 2024
05eb5f6
backward compatibility: migrate existing issuer key, patches and twea…
h2zh Nov 7, 2024
ab4da0c
use atomic pointer for the in-memory private keys map
h2zh Nov 7, 2024
e6a72f2
newIssuerKey API endpoint on origin, and unit tests
h2zh Nov 11, 2024
5ba6057
get the most recent modified private key from file dir, simply the code
h2zh Nov 12, 2024
04342d0
move the LaunchIssuerKeysDirRefresh func to origin service
h2zh Nov 15, 2024
e94c311
fix linting problem
h2zh Nov 18, 2024
54f48f5
use new config param IssuerKeysDirectory to replace IssuerKey
h2zh Nov 19, 2024
532cd05
fix linting problems
h2zh Nov 19, 2024
7b738d2
in docs, correct the scope of components affected by IssuerKeysDirectory
h2zh Nov 19, 2024
f4fdbd8
deprecate IssuerKey
h2zh Nov 19, 2024
09d3586
improve the naming of migrated key
h2zh Nov 19, 2024
a80f272
patch for the algorithm of new key regristration
h2zh Nov 21, 2024
a518afb
register namespace with new key (with TODO left)
h2zh Nov 22, 2024
dceede7
update namespace pubKey in registry db
h2zh Nov 22, 2024
8cb8090
update pubkey of all origin exports; align new key API and manual add…
h2zh Nov 27, 2024
473c5f3
improve how the registry authorize origin to address the security con…
h2zh Dec 2, 2024
007b7f1
Enhanced PoP using a "previous private key's signature"; previous act…
h2zh Dec 6, 2024
00b24c8
Avoid key file naming collision when running new and old codebase bac…
h2zh Dec 10, 2024
edc1250
Merge branch 'main' into multiple-private-keys
h2zh Dec 11, 2024
1fb11fd
Merge branch 'main' into multiple-private-keys
h2zh Dec 11, 2024
ac8eadf
handle old origin and a new registry (and vice versa); fix bug and ad…
h2zh Dec 13, 2024
da83225
fix semantic issues in PR review
h2zh Dec 16, 2024
6ae3260
detach Namespaces PubKey Update from Namespace Registration workflow
h2zh Dec 17, 2024
adcc5ee
reverts changes on namespace registration workflow in previous commits
h2zh Dec 17, 2024
0ea7e4f
fix linter issues
h2zh Dec 17, 2024
bc07e32
add unit tests to ensure public key update failures occur as expected
h2zh Dec 18, 2024
e3ca516
fix issues in follow-up reviews
h2zh Dec 18, 2024
e27231e
fix linter and go build tests
h2zh Dec 18, 2024
6ccb591
on registry, only rotate out the one previous key, then add the new k…
h2zh Dec 19, 2024
c26d95b
remove IssuerKey deprecated: true to avoid several failed tests
h2zh Dec 19, 2024
922a666
Merge branch 'main' into multiple-private-keys
h2zh Dec 19, 2024
9496706
attempt to fix failed TestRegistryKeyChainingOSDF on GH Action test (…
h2zh Dec 19, 2024
1ee5574
attempt to fix repeated-cache-access-not-found on GH Action test-ubuntu
h2zh Dec 19, 2024
8605720
fix deprecated-replacedby binding check
h2zh Dec 19, 2024
fc24a65
minor semantic improvement
h2zh Dec 19, 2024
2657575
attempt to fix API timeout "/api/v1.0/registry/updateNamespacesPubKey"
h2zh Dec 19, 2024
9d83986
another attempt to fix timeout
h2zh Dec 19, 2024
f1123dd
3rd attempt to fix timeout
h2zh Dec 20, 2024
08481cd
4th attempt to fix timeout
h2zh Dec 20, 2024
f3c7c99
5th attempt to fix timeout
h2zh Dec 20, 2024
7cc6591
6th attempt to fix timeout
h2zh Dec 20, 2024
0955e18
7th attempt to fix timeout
h2zh Dec 20, 2024
6162778
8th attempt to fix timeout
h2zh Dec 20, 2024
e9a0fb2
9th attempt to fix timeout
h2zh Dec 20, 2024
752ab32
10th attempt to fix timeout
h2zh Dec 20, 2024
0b1b7c1
10.5th attempt to fix timeout
h2zh Dec 20, 2024
d6dc0e1
11th attempt to fix timeout
h2zh Dec 20, 2024
5eb651f
12th attempt to fix timeout
h2zh Dec 20, 2024
85bc504
only run ./registry/registry_db_test.go and client_commands_test.go
h2zh Dec 20, 2024
1fec0ce
comment out TestServeNamespaceRegistry
h2zh Dec 20, 2024
9d03bd4
comment out TestServeNamespaceRegistry
h2zh Dec 20, 2024
08d3044
comment out both TestServeNamespaceRegistry and TestMultiPubKeysRegis…
h2zh Dec 20, 2024
6809e1d
test improvement
h2zh Dec 20, 2024
2c1ebd3
fix ResetCurrentIssuerKeysDir
h2zh Dec 20, 2024
ba42296
revert target tests in test-template.yml
h2zh Dec 20, 2024
7280e9d
Avoid deadlock when waiting on exit
bbockelm Dec 21, 2024
b6593ce
bring back TestServeNamespaceRegistry and TestMultiPubKeysRegisteredO…
h2zh Dec 23, 2024
896aa4b
comment out TestMultiPubKeysRegisteredOnNamespace
h2zh Dec 23, 2024
67b62f0
comment out TestServeNamespaceRegistry
h2zh Dec 23, 2024
7933e3c
generate a unique filename using a POSIX mkstemp-like logic; fix race…
h2zh Dec 27, 2024
e089e62
fix and refine private key i/o relevant funcs, remove risky api, crea…
h2zh Dec 31, 2024
a878208
attempt to solve timeout
h2zh Dec 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/generate_keygen.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func keygenMain(cmd *cobra.Command, args []string) error {
return errors.Wrap(err, "failed to get the current working directory")
}
if privateKeyPath == "" {
privateKeyPath = filepath.Join(wd, "issuer.jwk")
privateKeyPath = filepath.Join(wd, "issuer-keys")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work? Before, the variable was a file and now it's a directory. All the code below operates on this as if it was a directory.

On first glance, appears that the tool is broken, no?

Copy link
Collaborator Author

@h2zh h2zh Dec 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the private/public generation logic lies in config.GetIssuerPublicJWKS(), which was already updated to incorporate the new keys in IssuerKeysDirectory instead of only one key file at IssuerKey. The pelican generate keygen command works as expected (creating a key in ./issuer-keys).

} else {
privateKeyPath = filepath.Clean(strings.TrimSpace(privateKeyPath))
}
Expand Down Expand Up @@ -68,7 +68,7 @@ func keygenMain(cmd *cobra.Command, args []string) error {
return fmt.Errorf("file exists for public key under %s", publicKeyPath)
}

viper.Set(param.IssuerKey.GetName(), privateKeyPath)
viper.Set(param.IssuerKeysDirectory.GetName(), privateKeyPath)

// GetIssuerPublicJWKS will generate the private key at IssuerKey if it does not exist
// and parse the private key and generate the corresponding public key for us
Expand Down
9 changes: 2 additions & 7 deletions cmd/generate_keygen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ func setupTestRun(t *testing.T) string {
return tmpDir
}

func checkKeys(t *testing.T, privateKey, publicKey string) {
_, err := config.LoadPrivateKey(privateKey, false)
func checkKeys(t *testing.T, publicKey string) {
_, err := config.GetIssuerPrivateJWK()
require.NoError(t, err)

jwks, err := jwk.ReadFile(publicKey)
Expand Down Expand Up @@ -81,7 +81,6 @@ func TestKeygenMain(t *testing.T) {

checkKeys(
t,
filepath.Join(tempDir, "issuer.jwk"),
filepath.Join(tempDir, "issuer-pub.jwks"),
)
})
Expand All @@ -97,7 +96,6 @@ func TestKeygenMain(t *testing.T) {

checkKeys(
t,
privateKeyPath,
filepath.Join(tempWd, "issuer-pub.jwks"),
)
})
Expand All @@ -113,7 +111,6 @@ func TestKeygenMain(t *testing.T) {

checkKeys(
t,
filepath.Join(tempWd, "issuer.jwk"),
publicKeyPath,
)
})
Expand All @@ -130,7 +127,6 @@ func TestKeygenMain(t *testing.T) {

checkKeys(
t,
privateKeyPath,
filepath.Join(tempWd, "issuer-pub.jwks"),
)
})
Expand All @@ -147,7 +143,6 @@ func TestKeygenMain(t *testing.T) {

checkKeys(
t,
filepath.Join(tempWd, "issuer.jwk"),
publicKeyPath,
)
})
Expand Down
9 changes: 1 addition & 8 deletions cmd/registry_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ import (
"net/url"
"os"

"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/pelicanplatform/pelican/config"
"github.com/pelicanplatform/pelican/param"
"github.com/pelicanplatform/pelican/registry"
)

Expand Down Expand Up @@ -109,16 +107,11 @@ func registerANamespace(cmd *cobra.Command, args []string) {
os.Exit(1)
}

privateKeyRaw, err := config.LoadPrivateKey(param.IssuerKey.GetString(), false)
privateKey, err := config.GetIssuerPrivateJWK()
if err != nil {
log.Error("Failed to load private key", err)
os.Exit(1)
}
privateKey, err := jwk.FromRaw(privateKeyRaw)
if err != nil {
log.Error("Failed to create JWK private key", err)
os.Exit(1)
}

if withIdentity {
// We haven't added support to pass sitename from CLI, so leave it empty
Expand Down
5 changes: 4 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,7 @@ func SetServerDefaults(v *viper.Viper) error {
v.SetDefault(param.Xrootd_Authfile.GetName(), filepath.Join(configDir, "xrootd", "authfile"))
v.SetDefault(param.Xrootd_MacaroonsKeyFile.GetName(), filepath.Join(configDir, "macaroons-secret"))
v.SetDefault(param.IssuerKey.GetName(), filepath.Join(configDir, "issuer.jwk"))
v.SetDefault(param.IssuerKeysDirectory.GetName(), filepath.Join(configDir, "issuer-keys"))
h2zh marked this conversation as resolved.
Show resolved Hide resolved
v.SetDefault(param.Server_UIPasswordFile.GetName(), filepath.Join(configDir, "server-web-passwd"))
v.SetDefault(param.Server_UIActivationCodeFile.GetName(), filepath.Join(configDir, "server-web-activation-code"))
v.SetDefault(param.OIDC_ClientIDFile.GetName(), filepath.Join(configDir, "oidc-client-id"))
Expand Down Expand Up @@ -1438,7 +1439,7 @@ func InitServer(ctx context.Context, currentServers server_structs.ServerType) e

// As necessary, generate private keys, JWKS and corresponding certs

// Note: This function will generate a private key in the location stored by the viper var "IssuerKey"
// Note: This function will generate a private key in the location stored by the viper var "IssuerKeysDirectory"
// iff there isn't any valid private key present in that location
_, err = GetIssuerPublicJWKS()
if err != nil {
Expand Down Expand Up @@ -1489,6 +1490,8 @@ func SetClientDefaults(v *viper.Viper) error {
configDir := v.GetString("ConfigDir")

v.SetDefault(param.IssuerKey.GetName(), filepath.Join(configDir, "issuer.jwk"))
v.SetDefault(param.IssuerKeysDirectory.GetName(), filepath.Join(configDir, "issuer-keys"))
h2zh marked this conversation as resolved.
Show resolved Hide resolved

upperPrefix := GetPreferredPrefix()
if upperPrefix == OsdfPrefix || upperPrefix == StashPrefix {
v.SetDefault("Federation.TopologyNamespaceURL", "https://topology.opensciencegrid.org/osdf/namespaces")
Expand Down
14 changes: 6 additions & 8 deletions config/encrypted.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
Expand All @@ -42,8 +41,6 @@ import (
"golang.org/x/crypto/nacl/box"
"golang.org/x/term"
"gopkg.in/yaml.v3"

"github.com/pelicanplatform/pelican/param"
)

// If we prompted the user for a new password while setting up the file,
Expand Down Expand Up @@ -380,17 +377,18 @@ func SaveConfigContents_internal(config *OSDFConfig, forcePassword bool) error {
// Take a hash, and use the hash's bytes as the secret.
func GetSecret() (string, error) {
// Use issuer private key as the source to generate the secret
issuerKeyFile := param.IssuerKey.GetString()
err := GeneratePrivateKey(issuerKeyFile, elliptic.P256(), false)
privateKey, err := GetIssuerPrivateJWK()
if err != nil {
return "", err
}
privateKey, err := LoadPrivateKey(issuerKeyFile, false)
if err != nil {

// Extract the underlying ECDSA private key in native Go crypto key type
var rawKey interface{}
if err := privateKey.Raw(&rawKey); err != nil {
return "", err
}

derPrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey)
derPrivateKey, err := x509.MarshalPKCS8PrivateKey(rawKey)

if err != nil {
return "", err
Expand Down
20 changes: 10 additions & 10 deletions config/encrypted_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ func TestGetSecret(t *testing.T) {
})
t.Run("generate-32B-hash", func(t *testing.T) {
tmp := t.TempDir()
keyName := filepath.Join(tmp, "issuer.key")
viper.Set(param.IssuerKey.GetName(), keyName)
keyDir := filepath.Join(tmp, "issuer-keys")
viper.Set(param.IssuerKeysDirectory.GetName(), keyDir)

get, err := GetSecret()
require.NoError(t, err)
Expand All @@ -55,8 +55,8 @@ func TestEncryptString(t *testing.T) {

t.Run("encrypt-without-err", func(t *testing.T) {
tmp := t.TempDir()
keyName := filepath.Join(tmp, "issuer.key")
viper.Set(param.IssuerKey.GetName(), keyName)
keyDir := filepath.Join(tmp, "issuer-keys")
viper.Set(param.IssuerKeysDirectory.GetName(), keyDir)

get, err := EncryptString("Some secret to encrypt")
require.NoError(t, err)
Expand All @@ -72,8 +72,8 @@ func TestDecryptString(t *testing.T) {
})
t.Run("decrypt-without-err", func(t *testing.T) {
tmp := t.TempDir()
keyName := filepath.Join(tmp, "issuer.key")
viper.Set(param.IssuerKey.GetName(), keyName)
keyDir := filepath.Join(tmp, "issuer-keys")
viper.Set(param.IssuerKeysDirectory.GetName(), keyDir)

secret := "Some secret to encrypt"

Expand All @@ -88,17 +88,17 @@ func TestDecryptString(t *testing.T) {

t.Run("diff-secrets-yield-diff-result", func(t *testing.T) {
tmp := t.TempDir()
keyName := filepath.Join(tmp, "issuer.key")
viper.Set(param.IssuerKey.GetName(), keyName)
keyDir := filepath.Join(tmp, "issuer-keys")
viper.Set(param.IssuerKeysDirectory.GetName(), keyDir)

secret := "Some secret to encrypt"

getEncrypt, err := EncryptString(secret)
require.NoError(t, err)
assert.NotEmpty(t, getEncrypt)

newKeyName := filepath.Join(tmp, "new-issuer.key")
viper.Set(param.IssuerKey.GetName(), newKeyName)
newKeyDir := filepath.Join(tmp, "new-issuer-keys")
viper.Set(param.IssuerKeysDirectory.GetName(), newKeyDir)

getDecrypt, err := DecryptString(getEncrypt)
require.NoError(t, err)
Expand Down
Loading
Loading