keyprovider

package
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2024 License: MPL-2.0 Imports: 4 Imported by: 0

README

OpenTofu key providers

[!WARNING] This file is not an end-user documentation, it is intended for developers. Please follow the user documentation on the OpenTofu website unless you want to work on the encryption code.

This folder contains the interface that key providers must implement in order to work with OpenTofu. Please read this document carefully if you intend to work on a key provider.

What are key providers?

Key providers in OpenTofu are responsible for integrating various key-management systems or key derivation (passphrase) functions. They consist of 3 components:

  1. The descriptor provides a unique ID and a struct with HCL tags to read the configuration into.
  2. The configuration is a struct OpenTofu parses the user-supplied configuration into. The Build function on this struct creates the key provider itself.
  3. The key provider is responsible for creating one encryption key and one decryption key. It receives stored metadata and must return similar metadata in the result.

What is metadata?

Some key providers need to store data alongside the encrypted data, such as the salt, the hashing function name, the key length, etc. The key provider can use this metadata to recreate the exact same key for decryption as it used for encryption. However, the key provider could also provide a different key for each encryption and decryption, allowing for a quick rotation of encryption parameters.

[!WARNING] The metadata is bound to the key provider name. In order words, if you change the key provider name, OpenTofu will be unable to decrypt old data.

Implementing a key provider

When you implement a key provider, take a look at the static key provider as a template. You should never use this provider in production because it exposes users to certain weaknesses in some encryption methods, but it is a simple example for the structure.

Testing your provider (do this first!)

Before you even go about writing a key provider, please set up the compliance tests. You can create a single test case that calls compliancetest.ComplianceTest. This test suite will run your key provider through all important compliance tests and will make sure that you are not missing anything during the implementation.

Implementing the descriptor

The descriptor is very simple, you need to implement the Descriptor interface in a type. (It does not have to be a struct.) However, make sure that the ConfigStruct always returns a struct with hcl tags on it. For more information on the hcl tags, see the gohcl documentation.

The config struct

Next, you need to create a config structure. This structure should hold all the fields you expect a user to fill out. This must be a struct, and you must add hcl tags to each field you expect the user to fill out.

Additionally, you must implement the Build function described in the Config interface. You can take a look at static/config.go for an example on implementing this.

The metadata

The metadata can be anything as long as it's JSON-serializable, but we recommend using a struct for future extensibility. If you do not need metadata, simply use nil.

Think about what data you will need to decrypt data. For example, the user may change the key length in a key derivation function, but you still need the old key length to decrypt. Hence, it needs to be part of the metadata.

[!WARNING] The metadata is stored unencrypted and unauthenticated. Do not use it to store sensitive details and treat it as untrusted as it may contain malicious data.

The key provider

The heart of your key provider is... well, your key provider. It has two functions: to create a decryption key and to create an encryption key. If your key doesn't change, these two keys can be the same. However, if you generate new keys every time, you should provide the old key as the decryption key and the new key as the encryption key. If you need to pass along data to help with recreating the decryption key, you can use the metadata for that.

The output

Your key provider must emit the keyprovider.Output struct with the keys.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Addr

type Addr string

Addr is a type-alias for key provider address strings that identify a specific key provider configuration. The Addr is an opaque value. Do not perform string manipulation on it outside the functions supplied by the keyprovider package.

func NewAddr

func NewAddr(provider string, name string) (addr Addr, err hcl.Diagnostics)

NewAddr creates a new Addr type from the provider and name supplied. The Addr is a type-alias for key provider address strings that identify a specific key provider configuration. You should treat the value as opaque and not perform string manipulation on it outside the functions supplied by the keyprovider package.

func (Addr) Validate

func (a Addr) Validate() hcl.Diagnostics

Validate validates the Addr for formal naming conformance, but does not check if the referenced key provider actually exists in the configuration.

type Config

type Config interface {
	// Build provides a key provider and an empty JSON-tagged struct to read the decryption metadata into. If the
	// configuration is invalid, it returns an error.
	//
	// If a key provider does not need metadata, it may return nil.
	Build() (KeyProvider, KeyMeta, error)
}

Config is a struct annotated with HCL (and preferably JSON) tags that OpenTofu reads the user-provided configuration into. The Build function assembles the configuration into a usable key provider.

type Descriptor

type Descriptor interface {
	// ID returns the unique identifier used when parsing HCL or JSON configs.
	ID() ID

	// ConfigStruct creates a new configuration struct pointer annotated with hcl tags. The Build() receiver on
	// this struct must be able to build a KeyProvider from the configuration:
	//
	// Common errors:
	// - Returning a struct without a pointer
	// - Returning a non-struct
	ConfigStruct() Config
}

Descriptor is a high level description of a key provider.

type ErrInvalidConfiguration

type ErrInvalidConfiguration struct {
	Message string
	Cause   error
}

ErrInvalidConfiguration indicates that the key provider configuration is incorrect.

func (ErrInvalidConfiguration) Error

func (e ErrInvalidConfiguration) Error() string

func (ErrInvalidConfiguration) Unwrap

func (e ErrInvalidConfiguration) Unwrap() error

type ErrInvalidMetadata

type ErrInvalidMetadata struct {
	Message string
	Cause   error
}

ErrInvalidMetadata indicates that the key provider has received an incorrect metadata and cannot decrypt.

func (ErrInvalidMetadata) Error

func (e ErrInvalidMetadata) Error() string

func (ErrInvalidMetadata) Unwrap

func (e ErrInvalidMetadata) Unwrap() error

type ErrKeyProviderFailure

type ErrKeyProviderFailure struct {
	Message string
	Cause   error
}

ErrKeyProviderFailure indicates a generic key provider failure.

func (ErrKeyProviderFailure) Error

func (e ErrKeyProviderFailure) Error() string

func (ErrKeyProviderFailure) Unwrap

func (e ErrKeyProviderFailure) Unwrap() error

type ID

type ID string

ID is a type alias to make passing the wrong ID into a key provider harder.

func (ID) Validate

func (id ID) Validate() error

Validate validates the key provider ID for correctness.

type KeyMeta

type KeyMeta any

KeyMeta is a type alias for a struct annotated with JSON tags to store. Its purpose is to store parameters alongside the encrypted data which are required to later provide a decryption key.

Key providers can use this to store, for example, a randomly generated salt value which is required to later provide the same decryption key.

type KeyProvider

type KeyProvider interface {
	// Provide provides an encryption and decryption keys. If the process fails, it returns an error.
	//
	// The caller must pass in the same struct obtained from the Build function of the Config, with the decryption
	// metadata read in. If no decryption metadata is present, the caller must pass in the struct unmodified.
	Provide(decryptionMeta KeyMeta) (keysOutput Output, encryptionMeta KeyMeta, err error)
}

KeyProvider is the usable key provider. The Provide function is responsible for creating both the decryption and encryption key, as well as returning the metadata to be stored.

type Output

type Output struct {
	EncryptionKey []byte `hcl:"encryption_key" cty:"encryption_key" json:"encryption_key" yaml:"encryption_key"`
	DecryptionKey []byte `hcl:"decryption_key" cty:"decryption_key" json:"decryption_key" yaml:"decryption_key"`
}

Output is the standardized structure a key provider must return when providing a key. It contains two keys because some key providers may prefer include random data (e.g. salt) in the generated keys and this salt will be different for decryption and encryption.

func (*Output) Cty

func (o *Output) Cty() cty.Value

Cty turns the Output struct into a CTY value.

Directories

Path Synopsis
Package pbkdf2 contains a key provider that takes a passphrase and emits a PBKDF2 hash of the configured length.
Package pbkdf2 contains a key provider that takes a passphrase and emits a PBKDF2 hash of the configured length.
Package static contains a key provider that emits a static key.
Package static contains a key provider that emits a static key.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL