krot

package module
v0.1.0-beta.5 Latest Latest
Warning

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

Go to latest
Published: May 3, 2024 License: MIT Imports: 9 Imported by: 0

README

krot - Key Rotator Package

krot is a robust and flexible Go package designed to manage and rotate keys or secrets, such as those used to sign JWTs. It's built with customization in mind, allowing users to implement their own strategies by leveraging the interfaces provided.

Features

  • Flexible Key Rotator: krot provides a smooth way to rotate keys or secrets, ensuring your application's security is always up-to-date.
  • Customizable:
    • Interfaces: krot is designed to be adaptable to your needs. You can implement the provided interfaces to create a key rotation strategy that fits your application. Just by implementing one of thoses interfaces:KeyGenerator and KeyStorage.
    • Hooks: Enable the scheduling of triggers for events such as OnStart, OnStop, BeforeRotation, and AfterRotation. This feature empowers you to execute custom actions at crucial points in your application's lifecycle.
  • Easy to Use: With a simple and intuitive API, krot is easy to integrate into your Go applications.

Installation

To install the krot package, use the go get command:

go get -u github.com/zhaori96/krot

Usage

Here's a comprehensive guide on how to effectively use the krot package in various scenarios:

Basic Usage

A simple way to integrate krot into your application is by creating a rotator instance, starting it, and then fetching a key. Below is a basic example:

package main

import (
    "fmt"

    "github.com/zhaori96/krot"
)

func main() {
    rotator := krot.New()
    rotator.Start()
    defer rotator.Stop()

    key, err := rotator.GetKey()
    if err != nil {
        panic(err)
    }

    fmt.Printf("ID: %s; Value: %v; Expiration: %s", key.ID, key.Value, key.Expiration)
}

Using the Global Instance

You can simplify the process by utilizing the global instance provided by krot:

    krot.Start()
    defer krot.Stop()

    key, err := krot.GetKey()
    if err != nil {
        panic(err)
    }

    fmt.Printf("%v", key.ID)

Custom Settings

For more control over the key rotation process, you can customize the rotator settings. Here are two approaches:

Approach 1: Inline Settings

    settings := &krot.RotatorSettings{
        RotationKeyCount: 15,
        RotationInterval: krot.DefaultRotationInverval,
        KeyExpiration: krot.DefaultKeyExpiration,
        AutoClearExpiredKeys: false,
        KeyProvidingMode: krot.NonRepeatingCyclicKeyProvidingMode
    }

    rotator := krot.NewWithSettings(settings)

Approach 2: Default Settings with Overrides

    settings := krot.DefaultRotatorSettings()
    settings.RotationKeyCount = 15
    settings.AutoClearExpiredKeys = false
    settings.KeyProvidingMode = krot.NonRepeatingCyclicKeyProvidingMode

    rotator := krot.New()
    rotator.SetSettings(settings)

Hooks

Hooks allow you to execute custom logic before or after key rotation events. Use OnStart and OnStop hooks to perform actions when the Rotator starts or stops, respectively. Additionally, you can use BeforeRotation and AfterRotation hooks to execute logic before or after each key rotation.

// Example of using hooks
rotator.OnStart(func(r *krot.Rotator) {
	log.Println("Rotator is starting...")
})

rotator.OnStop(func(r *krot.Rotator) {
	log.Println("Rotator is stopping...")
})

rotator.BeforeRotation(func(r *krot.Rotator) {
	log.Println("Before key rotation...")
})

rotator.AfterRotation(func(r *krot.Rotator) {
	log.Println("After key rotation...")
})

KeyStorage with Redis

The RedisKeyStorage struct provides an implementation of the KeyStorage interface using Redis as the backend.

RedisKeyStorage Implementation
import (
    "context"
    "encoding/json"

    "github.com/go-redis/redis/v8"
)

type RedisKeyStorage struct {
    client *redis.Client
}

func NewRedisKeyStorage(client *redis.Client) *RedisKeyStorage {
    return &RedisKeyStorage{client: client}
}

func (r *RedisKeyStorage) Get(ctx context.Context, id string) (*Key, error) {
    val, err := r.client.Get(ctx, id).Result()
    if err == redis.Nil {
        return nil, ErrKeyNotFound
    } else if err != nil {
        return nil, err
    }

    var key Key
    err = json.Unmarshal([]byte(val), &key)
    if err != nil {
        return nil, err
    }

    return &key, nil
}

func (r *RedisKeyStorage) Add(ctx context.Context, keys ...*Key) error {
    for _, key := range keys {
        val, err := json.Marshal(key)
        if err != nil {
            return err
        }

        err = r.client.Set(ctx, key.ID, val, 0).Err()
        if err != nil {
            return err
        }
    }

    return nil
}

func (r *RedisKeyStorage) Delete(ctx context.Context, ids ...string) error {
    for _, id := range ids {
        err := r.client.Del(ctx, id).Err()
        if err != nil {
            return err
        }
    }

    return nil
}

func (r *RedisKeyStorage) Erase(ctx context.Context) error {
    return r.client.FlushDB(ctx).Err()
}

KeyGenerator with RSA

The KeyGenerator interface defines the contract for generating keys, with a specific implementation using RSA as the key type. This interface provides a method, Generate, which creates a new RSA key pair. If the key pair cannot be generated, it returns an error.

RSAKeyGenerator Implementation

Below is an example of implementing the KeyGenerator interface using RSA as the key type:

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"log"
	"os"
)

// RSAKeyGenerator implements the KeyGenerator interface using RSA as the key type.
type RSAKeyGenerator struct {
	KeySize int
}

// NewRSAKeyGenerator creates a new instance of RSAKeyGenerator with the specified key size.
func NewRSAKeyGenerator(keySize int) *RSAKeyGenerator {
	return &RSAKeyGenerator{
		KeySize: keySize,
	}
}

// Generate creates a new RSA key pair. If the key pair cannot be generated, it returns an error.
func (g *RSAKeyGenerator) Generate() (any, error) {
	// Generate RSA private key
	privateKey, err := rsa.GenerateKey(rand.Reader, g.KeySize)
	if err != nil {
		return nil, err
	}

	// Encode private key to PEM format
	privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}

	// Write private key to a file (for example purposes)
	privateKeyFile, err := os.Create("private_key.pem")
	if err != nil {
		return nil, err
	}
	defer privateKeyFile.Close()
	if err := pem.Encode(privateKeyFile, privateKeyPEM); err != nil {
		return nil, err
	}

	return privateKey, nil
}

Contribution

We welcome and appreciate contributions from the community! If you find any issues, have new features to propose, or want to improve the documentation, feel free to contribute to the krot project.

Documentation

Overview

package krot provides a comprehensive system for managing key rotation in secure applications. It includes components for generating, storing, and cleaning keys, as well as managing key rotation and expiration.

The key rotation system is controlled by a Rotator, which uses a KeyGenerator to create new keys, a KeyStorage to store and retrieve keys, and a KeyCleaner to remove expired keys. The Rotator can be started and stopped, and its operation can be customized with various settings.

The package also defines a Key type, which represents a key with an ID, value, and expiration time, and a KeyRotatorError type, which represents an error in the key rotation process.

Index

Constants

View Source
const (
	// DefaultRotationKeyCount is the default number of keys to rotate.
	DefaultRotationKeyCount int = 5

	// DefaultKeyExpiration is the default expiration time for a key.
	// The key expiration is calculated as follows:
	//   key expiration = current time + rotation interval + key expiration
	DefaultKeyExpiration time.Duration = 12 * time.Hour

	// DefaultRotationInterval is the default interval between rotations.
	// The rotation interval is calculated as follows:
	//   rotation interval = current time + rotation interval
	DefaultRotationInterval time.Duration = 12 * time.Hour
)

Variables

View Source
var (
	// ErrKeyNotFound is returned when a key is not found in the storage.
	ErrKeyNotFound = newError(ErrCodeKeyNotFound, "key not found")

	// ErrInvalidSettings is returned when the settings are invalid.
	ErrInvalidSettings = newError(ErrCodeInvalidSettings, "invalid settings")

	// ErrInvalidRotationKeyCount is returned when the rotation key count is invalid.
	ErrInvalidRotationKeyCount = newError(ErrCodeInvalidRotationKeyCount, "invalid rotation key count")

	// ErrInvalidRotationInterval is returned when the rotation interval is invalid.
	ErrInvalidRotationInterval = newError(ErrCodeInvalidRotationInterval, "invalid rotation interval")

	// ErrInvalidKeyExpiration is returned when the key expiration is invalid.
	ErrInvalidKeyExpiration = newError(ErrCodeInvalidKeyExpiration, "invalid key expiration")

	// ErrRotatorAlreadyRunning is returned when the rotator is already running.
	ErrRotatorAlreadyRunning = newError(ErrCodeRotatorAlreadyRunning, "rotator already running")

	// ErrNoKeysGenerated is returned when no keys were generated.
	ErrNoKeysGenerated = newError(ErrCodeNoKeysGenerated, "no keys generated")

	// ErrInvalidArgument is returned when an invalid argument is passed.
	ErrInvalidArgument = newError(ErrCodeInvalidArgument, "invalid argument")

	// ErrInvalidKeyProvidingMode is returned when the key providing mode is invalid.
	ErrInvalidKeyProvidingMode = newError(ErrCodeInvalidKeyProvidingMode, "invalid key providing mode")
)

Functions

func AfterRotation

func AfterRotation(hooks ...RotatorHook)

AfterRotation appends provided hooks to the end of the Rotator's hooksAfterRotation slice. These hooks are executed after a rotation occurs.

func AutoClearExpiredKeys

func AutoClearExpiredKeys() bool

AutoClearExpiredKeys returns the AutoClearExpiredKeys field of the Rotator's settings. It indicates whether the Rotator is configured to automatically clear expired keys.

func BeforeRotation

func BeforeRotation(hooks ...RotatorHook)

BeforeRotation appends provided hooks to the beginning of the Rotator's hooksBeforeRotation slice. These hooks are executed before a rotation occurs.

func GetKeyID

func GetKeyID() (string, error)

GetKeyID retrieves a random key ID from the Rotator. It returns the retrieved key ID and any error that occurred.

func ID

func ID() string

ID returns the unique identifier associated with the rotator. This identifier, generated upon creation, is used for storage and key generation.

func KeyExpiration

func KeyExpiration() time.Duration

KeyExpiration returns the KeyExpiration field of the Rotator's settings. It indicates the duration after which the keys generated by the Rotator are configured to expire.

func OnStart

func OnStart(hooks ...RotatorHook)

OnStart appends provided hooks that can be called when the Rotator starts.

func OnStop

func OnStop(hooks ...RotatorHook)

OnStop appends provided hooks that can be called when the Rotator stops.

func Rotate

func Rotate() error

Rotate generates a new set of keys and stores them in the Rotator's storage. It first sets the Rotator's state to Rotating, runs any BeforeRotation hooks, and then generates and stores the new keys. After storing the keys, it runs any AfterRotation hooks and sets the state back to Idle. It returns any error that occurred during the process.

func RotationInterval

func RotationInterval() time.Duration

RotationInterval returns the RotationInterval field of the Rotator's settings. It indicates the duration after which the Rotator is configured to rotate keys.

func RotationKeyCount

func RotationKeyCount() int

RotationKeyCount returns the RotationKeyCount field of the Rotator's settings. It indicates the number of keys the Rotator is configured to keep when rotating keys.

func SetGenerator

func SetGenerator(generator KeyGenerator) error

SetGenerator sets the generator field of the Rotator struct. It accepts a KeyGenerator type as an argument and returns an error. If the Rotator is currently active (i.e., r.status == RotatorStatusActive), the method immediately panics. This is a safety measure to prevent changing the generator while the Rotator is in use. If the provided KeyGenerator is nil, the method returns an ErrInvalidArgument.

func SetSettings

func SetSettings(settings *RotatorSettings) error

SetSettings sets the settings field of the Rotator struct. It accepts a RotatorSettings type as an argument and returns an error. If the Rotator is currently active (i.e., r.status == RotatorStatusActive), the method immediately panics. This is a safety measure to prevent changing the settings while the Rotator is in use. If the provided RotatorSettings is nil, or if the settings are invalid, the method returns an appropriate error.

func SetStorage

func SetStorage(storage KeyStorage) error

SetStorage sets the storage field of the Rotator struct. It accepts a KeyStorage type as an argument and returns an error. If the Rotator is currently active (i.e., r.status == RotatorStatusActive), the method immediately panics. This is a safety measure to prevent changing the storage while the Rotator is in use. If the provided KeyStorage is nil, the method returns an ErrInvalidArgument.

func Start

func Start() error

Start initiates the key rotation process. If components like the key generator, storage, rotation settings, rotation controller, or key cleaner are not set, they are initialized with default values. The Rotator's status is then set to active, and the rotation and cleaning processes are launched in separate goroutines.

If the Rotator is already active when Start is called, it returns an ErrRotatorAlreadyRunning error. If an error occurs during the initial key rotation, the error is returned and the Rotator does not start.

This method is safe for concurrent use.

Example:

rotator := NewRotator()
err := rotator.Start()
if err != nil {
    log.Fatal(err)
}
defer rotator.Stop()

If the Rotator starts successfully, Start returns nil.

func Stop

func Stop()

Stop halts the key rotation process. If the Rotator is already inactive, it immediately returns. Otherwise, it disposes the rotation controller, stops the key cleaner, and sets the Rotator's status to inactive.

This method is safe to call even if the Rotator is already stopped or has not been started. It ensures that the key rotation and cleaning processes are properly terminated.

Example:

rotator := NewRotator()
err := rotator.Start()
if err != nil {
    log.Fatal(err)
}
// ... use the rotator ...
rotator.Stop()

After calling Stop, the Rotator can be restarted with the Start method.

Types

type Key

type Key struct {
	ID      string    `json:"id"`
	Value   any       `json:"value"`
	Expires time.Time `json:"expires"`
}

Key represents a key with an ID, value, and expiration time. The ID is a unique identifier for the key. The value is the actual key data. The expiration time is the time at which the key expires.

func GetKey

func GetKey() (*Key, error)

GetKey retrieves a random key from the Rotator's storage. It returns the retrieved key and any error that occurred.

func GetKeyByID

func GetKeyByID(id string) (*Key, error)

GetKeyByID retrieves a key from the Rotator's storage by its ID. It returns the retrieved key and any error that occurred.

func (*Key) Expired

func (k *Key) Expired() bool

Expired checks if the key has expired. It returns true if the key's expiration time is before the current time, and false otherwise.

if key.Expired() {
    fmt.Println("The key has expired.")
} else {
    fmt.Println("The key has not expired.")
}

type KeyCleaner

type KeyCleaner interface {
	// State returns the current state of the cleaner.
	State() KeyCleanerState

	// Status returns the current status of the cleaner.
	Status() KeyCleanerStatus

	// OnStart registers hooks to be executed when the cleaner starts.
	OnStart(hooks ...KeyCleanerHook)

	// OnStop registers hooks to be executed when the cleaner stops.
	OnStop(hooks ...KeyCleanerHook)

	// BeforeCleaning registers hooks to be executed before the cleaner starts cleaning.
	BeforeCleaning(hooks ...KeyCleanerHook)

	// AfterCleaning registers hooks to be executed after the cleaner finishes cleaning.
	AfterCleaning(hooks ...KeyCleanerHook)

	// Start begins the key cleaning process. It requires a context for managing
	Start(ctx context.Context, interval time.Duration) error

	// Stop halts the key cleaning process.
	Stop()
}

func NewKeyCleaner

func NewKeyCleaner(storage KeyStorage) KeyCleaner

type KeyCleanerHook

type KeyCleanerHook func(cleaner KeyCleaner)

KeyCleanerHook defines the signature for key cleaner hooks.

type KeyCleanerHooks

type KeyCleanerHooks []KeyCleanerHook

KeyCleanerHooks defines a collection of key cleaner hooks.

func (KeyCleanerHooks) Run

func (h KeyCleanerHooks) Run(cleaner KeyCleaner)

Run executes the key cleaner hooks.

type KeyCleanerState

type KeyCleanerState uint

KeyCleanerState defines the state of the key cleaner.

const (
	// KeyCleanerStateIdle represents the idle state of the cleaner.
	KeyCleanerStateIdle KeyCleanerState = iota

	// KeyCleanerStateCleaning represents the cleaning state of the cleaner.
	KeyCleanerStateCleaning
)

type KeyCleanerStatus

type KeyCleanerStatus uint

KeyCleanerStatus defines the status of the key cleaner.

const (
	// KeyCleanerStatusStopped represents the stopped status of the cleaner.
	KeyCleanerStatusStopped KeyCleanerStatus = iota

	// KeyCleanerStatusStarted represents the started status of the cleaner.
	KeyCleanerStatusStarted
)

type KeyGenerator

type KeyGenerator interface {
	// Generate creates a new key. If the key cannot be generated, it returns an error.
	//
	//     key, err := generator.Generate()
	//     if err != nil {
	//         log.Fatal(err)
	//     }
	Generate() (any, error)
}

KeyGenerator defines the interface for generating keys. It provides a method for generating a key.

func NewKeyGenerator

func NewKeyGenerator(size KeySize) KeyGenerator

type KeyIDProvider

type KeyIDProvider struct {
	// contains filtered or unexported fields
}

KeyIDProvider manages the provision of keys (IDs) based on a specified strategy.

func NewKeyIDProvider

func NewKeyIDProvider(mode KeyProvidingMode, ids ...string) *KeyIDProvider

NewKeyIDProvider returns a new KeyIDProvider with the specified mode and IDs.

func (*KeyIDProvider) Get

func (i *KeyIDProvider) Get() (string, error)

Get returns an ID based on the current KeyProvidingMode. If no IDs are available, it returns an error. The behavior varies depending on the mode:

func (*KeyIDProvider) Set

func (s *KeyIDProvider) Set(ids ...string)

Set replaces the existing IDs in the KeyIDProvider with the provided IDs. Note that any previous IDs are lost when this method is called.

type KeyProvidingMode

type KeyProvidingMode int

KeyProvidingMode represents the strategy used for providing keys.

const (
	// AutoKeyProvidingMode: This mode automatically selects the key providing
	// strategy based on the number of keys:
	// 	- Single key: Always returns the single available key.
	// 	- Two to five keys: Uses NonRepeatingKeyProvidingMode.
	// 	- More than five keys: Uses NonRepeatingCyclicKeyProvidingMode.
	AutoKeyProvidingMode KeyProvidingMode = iota

	// RandomKeyProvidingMode: This mode randomly selects a key from the
	// available keys. The same key can be selected multiple times in a row.
	RandomKeyProvidingMode

	// NonRepeatingKeyProvidingMode: This mode randomly selects a key from the
	// available keys, but ensures that the same key is not selected twice in a row.
	NonRepeatingKeyProvidingMode

	// CyclicKeyProvidingMode: This mode cycles through the keys in order,
	// starting from the first key and returning to the first key after the last key.
	CyclicKeyProvidingMode

	// NonRepeatingCyclicKeyProvidingMode: This mode cycles through the keys in
	// order, but ensures that the same key is not selected twice in a row.
	// After all keys have been selected, it starts a new cycle.
	NonRepeatingCyclicKeyProvidingMode
)

type KeySize

type KeySize int
const (
	KeySize32  KeySize = 4
	KeySize64  KeySize = 8
	KeySize128 KeySize = 16
	KeySize192 KeySize = 24
	KeySize256 KeySize = 32
	KeySize512 KeySize = 64
)

type KeyStorage

type KeyStorage interface {
	// Get retrieves a key with the specified ID from the storage. If the key is not
	// found, it returns an error.
	//
	//     key, err := storage.Get(ctx, "keyID")
	//     if err != nil {
	//         log.Fatal(err)
	//     }
	Get(context context.Context, id string) (*Key, error)

	// Add adds one or more keys to the storage. If a key cannot be added, it returns
	// an error.
	//
	//     err := storage.Add(ctx, key1, key2)
	//     if err != nil {
	//         log.Fatal(err)
	//     }
	Add(context context.Context, keys ...*Key) error

	// Delete removes a key with the specified ID from the storage. If the key cannot
	// be deleted, it returns an error.
	//
	//     err := storage.Delete(ctx, "keyID")
	//     if err != nil {
	//         log.Fatal(err)
	//     }
	Delete(context context.Context, ids ...string) error

	// ClearDeprecated iterates over the keys in the storage and removes any keys that are either nil or expired.
	// It returns an error if any issues occur during the operation.
	//
	//     err := storage.ClearDeprecated(ctx)
	//     if err != nil {
	//         log.Fatal(err)
	//     }
	ClearDeprecated(context context.Context) error

	// Erase removes all keys from the storage. If the keys cannot be erased, it
	// returns an error.
	//
	//     err := storage.Erase(ctx)
	//     if err != nil {
	//         log.Fatal(err)
	//     }
	Erase(context context.Context) error
}

KeyStorage defines the interface for key storage operations. It provides methods for getting, adding, deleting, and erasing keys.

func NewKeyStorage

func NewKeyStorage() KeyStorage

type KrotError

type KrotError interface {
	// Code returns the error code.
	Code() KrotErrorCode
	// Cause returns the cause of the error.
	Cause() error
	// Wrap wraps the error with the cause.
	Wrap(err error) error
	// Error returns the error message.
	Error() string
}

type KrotErrorCode

type KrotErrorCode int

KrotErrorCode is an integer type used to represent different types of errors in the application.

const (

	// ErrCodeInvalidRotationKeyCount is used when the rotation key count is invalid.
	ErrCodeInvalidRotationKeyCount KrotErrorCode

	// ErrCodeInvalidRotationInterval is used when the rotation interval is invalid.
	ErrCodeInvalidRotationInterval

	// ErrCodeInvalidKeyExpiration is used when the key expiration is invalid.
	ErrCodeInvalidKeyExpiration

	// ErrCodeInvalidArgument is used when an invalid argument is passed.
	ErrCodeInvalidArgument

	// ErrCodeInvalidKeyProvidingMode is used when the key providing mode is invalid.
	ErrCodeInvalidKeyProvidingMode
)
const (

	// ErrCodeRotatorAlreadyRunning is used when the rotator is already running.
	ErrCodeRotatorAlreadyRunning KrotErrorCode

	// ErrCodeNoKeysGenerated is used when no keys were generated.
	ErrCodeNoKeysGenerated
)
const (

	// ErrCodeInvalidSettings is used when the settings provided are invalid.
	ErrCodeInvalidSettings KrotErrorCode
)
const (

	// ErrCodeKeyNotFound is used when a key is not found in the storage.
	ErrCodeKeyNotFound KrotErrorCode
)

type RotationController

type RotationController struct {
	// contains filtered or unexported fields
}

func NewRotationController

func NewRotationController() *RotationController

func (*RotationController) Context

func (c *RotationController) Context() context.Context

func (*RotationController) Disposed

func (c *RotationController) Disposed() bool

func (*RotationController) Lock

func (c *RotationController) Lock()

func (*RotationController) TurnOff

func (c *RotationController) TurnOff()

func (*RotationController) TurnOn

func (c *RotationController) TurnOn()

func (*RotationController) Unlock

func (c *RotationController) Unlock()

type Rotator

type Rotator struct {
	// contains filtered or unexported fields
}

Rotator is a concurrent-safe key rotation manager. It generates and stores new keys at regular intervals while cleaning up expired keys. Suitable for rotating keys in encryption, decryption, signing, verification, and authentication.

func FromContext

func FromContext(ctx context.Context, alias ...string) *Rotator

FromContext retrieves the Rotator linked with the given context. If no alias is specified, it returns the Rotator associated with the default alias "default". If an alias is provided, it returns the Rotator associated with that specific alias. If no Rotator is linked with the context (or the specified alias), it returns nil.

Example wihtout alias:

rotator, ctx := krot.NewWithContext(context.Background())
krot.FromContext(ctx).Start() // Starts the default rotator

Example with alias:

rotator, ctx := krot.NewWithContext(context.Background(), "my-rotator")
krot.FromContext(ctx, "my-rotator").Start() // Starts the rotator with the alias "my-rotator"

func GetRotator

func GetRotator() *Rotator

GetRotator returns the global instance of the Rotator.

func New

func New() *Rotator

New returns a newly initialized key rotator with default settings, storage, and key generator. Settings, storage and key generator can be set using the SetSettings, SetStorage, and SetGenerator methods.

func NewWithContext

func NewWithContext(ctx context.Context, alias ...string) (*Rotator, context.Context)

NewWithContext initializes a key rotator with default settings, storage, and key generator. It returns the rotator and a context that has the rotator associated with it. You can customize the rotator by using SetSettings, SetStorage, and SetGenerator methods.

The rotator can be retrieved from the context using FromContext method.

If an alias is provided, it's used to associate the rotator with the context. This allows for multiple rotators to be associated with a single context.

If no alias is provided, the rotator is associated with the context using the default alias "default".

Example without alias:

rotator, ctx := krot.NewWithContext(context.Background())
krot.FromContext(ctx).Start() // Starts the default rotator

Example with alias:

rotator, ctx := krot.NewWithContext(context.Background(), "my-rotator")
krot.FromContext(ctx, "my-rotator").Start() // Starts the rotator with the alias "my-rotator"

func NewWithSettings

func NewWithSettings(settings *RotatorSettings) (*Rotator, error)

NewWithSettings returns a newly initialized key rotator with the given settings. Storage and key generator can be set using the SetStorage and SetGenerator methods.

func (*Rotator) AfterRotation

func (r *Rotator) AfterRotation(hooks ...RotatorHook)

AfterRotation appends provided hooks to the end of the Rotator's hooksAfterRotation slice. These hooks are executed after a rotation occurs.

func (*Rotator) AutoClearExpiredKeys

func (r *Rotator) AutoClearExpiredKeys() bool

AutoClearExpiredKeys returns the AutoClearExpiredKeys field of the Rotator's settings. It indicates whether the Rotator is configured to automatically clear expired keys.

func (*Rotator) BeforeRotation

func (r *Rotator) BeforeRotation(hooks ...RotatorHook)

BeforeRotation appends provided hooks to the beginning of the Rotator's hooksBeforeRotation slice. These hooks are executed before a rotation occurs.

func (*Rotator) GetKey

func (r *Rotator) GetKey() (*Key, error)

GetKey retrieves a random key from the Rotator's storage. It returns the retrieved key and any error that occurred.

func (*Rotator) GetKeyByID

func (r *Rotator) GetKeyByID(id string) (*Key, error)

GetKeyByID retrieves a key from the Rotator's storage by its ID. It returns the retrieved key and any error that occurred.

func (*Rotator) GetKeyID

func (r *Rotator) GetKeyID() (string, error)

GetKeyID retrieves a random key ID from the Rotator. It returns the retrieved key ID and any error that occurred.

func (*Rotator) ID

func (r *Rotator) ID() string

ID returns the unique identifier associated with the rotator. This identifier, generated upon creation, is used for storage and key generation.

func (*Rotator) KeyExpiration

func (r *Rotator) KeyExpiration() time.Duration

KeyExpiration returns the KeyExpiration field of the Rotator's settings. It indicates the duration after which the keys generated by the Rotator are configured to expire.

func (*Rotator) OnStart

func (r *Rotator) OnStart(hooks ...RotatorHook)

OnStart appends provided hooks that can be called when the Rotator starts.

func (*Rotator) OnStop

func (r *Rotator) OnStop(hooks ...RotatorHook)

OnStop appends provided hooks that can be called when the Rotator stops.

func (*Rotator) Rotate

func (r *Rotator) Rotate() error

Rotate generates a new set of keys and stores them in the Rotator's storage. It first sets the Rotator's state to Rotating, runs any BeforeRotation hooks, and then generates and stores the new keys. After storing the keys, it runs any AfterRotation hooks and sets the state back to Idle. It returns any error that occurred during the process.

func (*Rotator) RotationInterval

func (r *Rotator) RotationInterval() time.Duration

RotationInterval returns the RotationInterval field of the Rotator's settings. It indicates the duration after which the Rotator is configured to rotate keys.

func (*Rotator) RotationKeyCount

func (r *Rotator) RotationKeyCount() int

RotationKeyCount returns the RotationKeyCount field of the Rotator's settings. It indicates the number of keys the Rotator is configured to keep when rotating keys.

func (*Rotator) SetGenerator

func (r *Rotator) SetGenerator(generator KeyGenerator) error

SetGenerator sets the generator field of the Rotator struct. It accepts a KeyGenerator type as an argument and returns an error. If the Rotator is currently active (i.e., r.status == RotatorStatusActive), the method immediately panics. This is a safety measure to prevent changing the generator while the Rotator is in use. If the provided KeyGenerator is nil, the method returns an ErrInvalidArgument.

func (*Rotator) SetSettings

func (r *Rotator) SetSettings(settings *RotatorSettings) error

SetSettings sets the settings field of the Rotator struct. It accepts a RotatorSettings type as an argument and returns an error. If the Rotator is currently active (i.e., r.status == RotatorStatusActive), the method immediately panics. This is a safety measure to prevent changing the settings while the Rotator is in use. If the provided RotatorSettings is nil, or if the settings are invalid, the method returns an appropriate error.

func (*Rotator) SetStorage

func (r *Rotator) SetStorage(storage KeyStorage) error

SetStorage sets the storage field of the Rotator struct. It accepts a KeyStorage type as an argument and returns an error. If the Rotator is currently active (i.e., r.status == RotatorStatusActive), the method immediately panics. This is a safety measure to prevent changing the storage while the Rotator is in use. If the provided KeyStorage is nil, the method returns an ErrInvalidArgument.

func (*Rotator) Start

func (r *Rotator) Start() error

Start initiates the key rotation process. If components like the key generator, storage, rotation settings, rotation controller, or key cleaner are not set, they are initialized with default values. The Rotator's status is then set to active, and the rotation and cleaning processes are launched in separate goroutines.

If the Rotator is already active when Start is called, it returns an ErrRotatorAlreadyRunning error. If an error occurs during the initial key rotation, the error is returned and the Rotator does not start.

This method is safe for concurrent use.

Example:

rotator := NewRotator()
err := rotator.Start()
if err != nil {
    log.Fatal(err)
}
defer rotator.Stop()

If the Rotator starts successfully, Start returns nil.

func (*Rotator) State

func (r *Rotator) State() RotatorState

State returns the current state of the rotator, which is either idle or rotating. The rotator is considered idle when not rotating and marked as rotating when in operation.

func (*Rotator) Status

func (r *Rotator) Status() RotatorStatus

Status returns the current operational status of the rotator, which is either active or inactive. The rotator is considered active while running and marked as inactive when not in operation.

func (*Rotator) Stop

func (r *Rotator) Stop()

Stop halts the key rotation process. If the Rotator is already inactive, it immediately returns. Otherwise, it disposes the rotation controller, stops the key cleaner, and sets the Rotator's status to inactive.

This method is safe to call even if the Rotator is already stopped or has not been started. It ensures that the key rotation and cleaning processes are properly terminated.

Example:

rotator := NewRotator()
err := rotator.Start()
if err != nil {
    log.Fatal(err)
}
// ... use the rotator ...
rotator.Stop()

After calling Stop, the Rotator can be restarted with the Start method.

type RotatorHook

type RotatorHook func(rotator *Rotator)

RotatorHook is a function that is called before or after a rotation.

var (
	// EraseStorageHook is a predefined function that implements the RotatorHook interface.
	// When executed, it erases all keys from the associated Rotator's storage.
	// This is achieved by creating a new background context and invoking the Erase method of the Rotator's storage.
	// This hook is typically used when you want to clear all keys from the storage, such as during starting or stopping of the Rotator.
	//
	// Example usage:
	// 	rotator.OnStart(krot.EraseStorageHook)
	EraseStorageHook RotatorHook = func(rotator *Rotator) {
		rotator.storage.Erase(context.Background())
	}
)

type RotatorHooks

type RotatorHooks []RotatorHook

RotatorHooks is a collection of RotatorHook functions. It implements the Run method which runs all the hooks in the collection.

func (RotatorHooks) Run

func (h RotatorHooks) Run(rotator *Rotator)

type RotatorSettings

type RotatorSettings struct {
	// RotationKeyCount is the number of keys to rotate.
	// The default value is DefaultRotationKeyCount.
	// The minimum value is 1.
	RotationKeyCount int

	// KeyExpiration is the expiration time for a key.
	// The default value is DefaultKeyExpiration.
	KeyExpiration time.Duration

	// RotationInterval is the interval between rotations.
	// The default value is DefaultRotationInterval.
	RotationInterval time.Duration

	// ExtendExpiration determines if the expiration of keys should be extended by the RotationInterval.
	// This ensures that there is always a valid key during rotation transitions.
	// The default value is true.
	ExtendExpiration bool

	// AutoClearExpiredKeys is a flag that indicates whether to automatically clear expired keys.
	// The default value is true.
	AutoClearExpiredKeys bool

	// KeyProvidingMode is the strategy used for providing keys.
	// The default value is AutoKeyProvidingMode.
	KeyProvidingMode KeyProvidingMode
}

RotatorSettings is the settings for the rotator.

func DefaultRotatorSettings

func DefaultRotatorSettings() *RotatorSettings

DefaultRotatorSettings returns the default rotator settings.

func (*RotatorSettings) Validate

func (s *RotatorSettings) Validate() error

Validate validates the rotator settings.

type RotatorState

type RotatorState uint

RotatorState is the state of the rotator.

const (
	// RotatorStateIdle is the state of the rotator when it is not rotating.
	RotatorStateIdle RotatorState = iota

	// RotatorStateRotating is the state of the rotator when it is rotating.
	RotatorStateRotating
)

func State

func State() RotatorState

State returns the current state of the rotator, which is either idle or rotating. The rotator is considered idle when not rotating and marked as rotating when in operation.

type RotatorStatus

type RotatorStatus uint

RotatorStatus is the status of the rotator.

const (
	// RotatorStatusStopped is the status of the rotator when it is not running.
	RotatorStatusStopped RotatorStatus = iota

	// RotatorStatusStarted is the status of the rotator when it is running.
	RotatorStatusStarted
)

func Status

func Status() RotatorStatus

Status returns the current operational status of the rotator, which is either active or inactive. The rotator is considered active while running and marked as inactive when not in operation.

Directories

Path Synopsis
examples/jwt_hook.go
examples/jwt_hook.go

Jump to

Keyboard shortcuts

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