-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial KeyStore implementation (#3329)
Relates to #3304 Implement an interface which hides the specifics of loading an encryption key. This allows us to use a secret store or a key store directly in future. Right now, the implementation uses a single key loaded from the config. In my next PR, I will generalize it to support multiple keys. This will require a new config structure.
- Loading branch information
Showing
6 changed files
with
229 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright 2024 Stacklok, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package algorithms contains implementations of various crypto algorithms | ||
// for the crypto engine. | ||
package algorithms | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
// EncryptionAlgorithm represents a crypto algorithm used by the Engine | ||
type EncryptionAlgorithm interface { | ||
Encrypt(data []byte, key []byte, salt []byte) ([]byte, error) | ||
Decrypt(data []byte, key []byte, salt []byte) ([]byte, error) | ||
} | ||
|
||
// Type is an enum of supported encryption algorithms | ||
type Type string | ||
|
||
const ( | ||
// Aes256Cfb is the AES-256-CFB algorithm | ||
Aes256Cfb Type = "aes-256-cfb" | ||
) | ||
|
||
const maxSize = 32 * 1024 * 1024 | ||
|
||
// ErrUnknownAlgorithm is used when an incorrect algorithm name is used. | ||
var ( | ||
ErrUnknownAlgorithm = errors.New("unexpected encryption algorithm") | ||
) | ||
|
||
// TypeFromString attempts to map a string to a `Type` value. | ||
func TypeFromString(name string) (Type, error) { | ||
// TODO: use switch when we support more than once type. | ||
if name == string(Aes256Cfb) { | ||
return Aes256Cfb, nil | ||
} | ||
return "", fmt.Errorf("%w: %s", ErrUnknownAlgorithm, name) | ||
} | ||
|
||
// NewFromType instantiates an encryption algorithm by name | ||
func NewFromType(algoType Type) (EncryptionAlgorithm, error) { | ||
// TODO: use switch when we support more than once type. | ||
if algoType == Aes256Cfb { | ||
return &AES256CFBAlgorithm{}, nil | ||
} | ||
return nil, fmt.Errorf("%w: %s", ErrUnknownAlgorithm, algoType) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright 2024 Stacklok, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package keystores contains logic for loading encryption keys from a keystores | ||
package keystores | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"path/filepath" | ||
|
||
serverconfig "github.com/stacklok/minder/internal/config/server" | ||
) | ||
|
||
//go:generate go run go.uber.org/mock/mockgen -package mock_$GOPACKAGE -destination=./mock/$GOFILE -source=./$GOFILE | ||
|
||
// KeyStore represents a struct which stores or can fetch encryption keys. | ||
type KeyStore interface { | ||
// GetKey retrieves the key for the specified algorithm by key ID. | ||
GetKey(id string) ([]byte, error) | ||
} | ||
|
||
// ErrUnknownKeyID is returned when the Key ID cannot be found by the keystore. | ||
var ErrUnknownKeyID = errors.New("unknown key id") | ||
|
||
// This structure is used by the keystore implementation to manage keys. | ||
type keysByID map[string][]byte | ||
|
||
// NewKeyStoreFromConfig creates an instance of a KeyStore based on the | ||
// AuthConfig in Minder. | ||
// Since our only implementation is based on reading from the local disk, do | ||
// all key loading during construction of the struct. | ||
// TODO: allow support for multiple keys/algos | ||
func NewKeyStoreFromConfig(config *serverconfig.AuthConfig) (KeyStore, error) { | ||
key, err := config.GetTokenKey() | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to read encryption key from %s: %w", config.TokenKey, err) | ||
} | ||
// Use the key filename as the key ID. | ||
name := filepath.Base(config.TokenKey) | ||
keys := map[string][]byte{ | ||
name: key, | ||
} | ||
return &localFileKeyStore{ | ||
keys: keys, | ||
}, nil | ||
} | ||
|
||
type localFileKeyStore struct { | ||
keys keysByID | ||
} | ||
|
||
func (l *localFileKeyStore) GetKey(id string) ([]byte, error) { | ||
key, ok := l.keys[id] | ||
if !ok { | ||
return nil, fmt.Errorf("%w: %s", ErrUnknownKeyID, id) | ||
} | ||
return key, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.