redactr

package module
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Nov 22, 2019 License: MIT Imports: 9 Imported by: 0

README

redactr

Build Status Go Report Card

redactr replaces secrets with Redacted Secrets.

With the right privileges, redactr can replace Redacted Secrets with secrets.

Table of Contents

Install

Binary

Binaries are available on the releases page

Brew (Mac OS)
brew tap dhoelle/tap
brew install dhoelle/tap/redactr
Build from source

Requires Go >1.11

go get github.com/dhoelle/redactr/cmd/redactr

Example (CLI)

First, set some environment variables, which redactr will use to redact and unredact secrets:

export AES_KEY="xuY6/V0ZE29RtPD3TNWga/EkdU3XYsPtBIk8U4nzZyc="
export VAULT_ADDR=http://localhost:8200
export VAULT_TOKEN=my_token
Redact secrets
redactr redact <<EOF
My email password is ~~redact:hunter2~~
My database password is ~~redact-vault:path/to/kv/secret#my_key#swordfish~~
EOF
# output:
# My email password is ~~redacted-aes:DYeT3hCH1unjeWl9whMhjn/ILcM3r24XaX7xgWO8sOJkvCs=~~
# My database password is ~~redacted-vault:path/to/kv/secret#my_key~
Unredact secrets
redactr unredact <<EOF
My email password is ~~redacted-aes:DYeT3hCH1unjeWl9whMhjn/ILcM3r24XaX7xgWO8sOJkvCs=~~
My database password is ~~redacted-vault:path/to/kv/secret#my_key~~
EOF
# output:
# My email password is hunter2
# My database password is swordfish

By default secrets are unredacted without the original secret wrapping. You can add it back with the -w/--wrap-tokens flag:

redactr unredact -w <<EOF
My email password is ~~redacted-aes:DYeT3hCH1unjeWl9whMhjn/ILcM3r24XaX7xgWO8sOJkvCs=~~
My database password is ~~redacted-vault:path/to/kv/secret#my_key~~
EOF
# output:
# My email password is ~~redact:hunter2~~
# My database password is ~~redact-vault:path/to/kv/secret#my_key#swordfish~~
Execute commands

redactr exec executes commands with redacted secrets in its environment

PASSWORD="~~redacted-aes:DYeT3hCH1unjeWl9whMhjn/ILcM3r24XaX7xgWO8sOJkvCs=~~" \
redactr exec echo 'my password is $PASSWORD'
# output: my password is hunter2
Re-evaluating the environment

Some redactr secrets are dynamic. For example, passwords in a vault instance can change over time.

redactr exec can be configured to periodically unredact the secrets that a command uses and, if they have changed, either stop or restart the command.

The following example creates a local vault instance and changes a password every second, then runs a command with redactr exec which re-runs on each change:

# Start a local vault instance
docker run -d --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' -p 8222:8200 vault
sleep 1

# Start a background job which changes a secret every second for 20 seconds
func changesecrets() {
    for i in {1..10}
    do
        VAULT_ADDR=http://0.0.0.0:8222 VAULT_TOKEN=myroot vault kv put secret/db_password value=hunter2
        sleep 1
        VAULT_ADDR=http://0.0.0.0:8222 VAULT_TOKEN=myroot vault kv put secret/db_password value=swordfish
        sleep 1
    done
}
changesecrets &>/dev/null &
sleep 1

# use `redactr exec` to print the secret and block.
# Each time the secret changes, the command will
# restart and the new secret will be printed.
VAULT_ADDR=http://localhost:8222 \
VAULT_TOKEN=myroot \
SECRET_KEY=~~redacted-vault:secret/data/db_password#value~~ \
redactr exec \
    -r 1000ms
    /bin/bash -c 'echo "$(date): secret key: $SECRET_KEY"; sleep 3'

# example output:
# Tue Apr 30 18:42:24 PDT 2019: secret key: swordfish
# Tue Apr 30 18:42:25 PDT 2019: secret key: hunter2
# Tue Apr 30 18:42:26 PDT 2019: secret key: swordfish
# ...

Example (Go Library)

package main

import (
	"fmt"
	"log"

	"github.com/dhoelle/redactr"
)

func main() {
	c, _ := redactr.New(
		redactr.AESKey("xuY6/V0ZE29RtPD3TNWga/EkdU3XYsPtBIk8U4nzZyc="),
	)

	plaintext := "foo ~~redact:hunter2~~ baz"
    redacted, _ := c.RedactTokens(plaintext)
    fmt.Println(redacted) // "foo secret-encrypted:DYeT3hCH1unjeWl9whMhjn/ILcM3r24XaX7xgWO8sOJkvCs=~~-encrypted baz"

    unredacted, _ := c.UnredactTokens(redacted)
    fmt.Println(redacted) // "foo hunter2 baz"

    unredacted, _ = c.UnredactTokens(redacted, redactr.WrapTokens)
    fmt.Println(redacted) // "foo ~~redact:hunter2~~ baz"
}

Example (Docker)

A docker image is available: https://cloud.docker.com/repository/docker/dhoelle/redactr

$ docker run \
    -e AES_KEY="xuY6/V0ZE29RtPD3TNWga/EkdU3XYsPtBIk8U4nzZyc=" \
    dhoelle/redactr \
    unredact "~~redacted-aes:DYeT3hCH1unjeWl9whMhjn/ILcM3r24XaX7xgWO8sOJkvCs=~~"

# output:
# hunter2

Secret types

type unredacted form redacted form
local secret redact:* redacted-aes:*
vault KV secret redact-vault:path/to/secret#key#value redacted-vault:path/to/secret#key
Encrypted secrets (AES-256-GCM)

Secrets can be redacted via 256-bit AES-GCM encryption.

$ redactr key
xuY6/V0ZE29RtPD3TNWga/EkdU3XYsPtBIk8U4nzZyc=

$ export AES_KEY="xuY6/V0ZE29RtPD3TNWga/EkdU3XYsPtBIk8U4nzZyc="

$ redactr redact "~~redact:hunter2~~"
~~redacted-aes:JOf+CmAfgyCSbesz6zstfUx7gHIuJ/JMeyyf8UqCGvkxjkc=~~

$ redactr unredact "~~redacted-aes:JOf+CmAfgyCSbesz6zstfUx7gHIuJ/JMeyyf8UqCGvkxjkc=~~"
hunter2

# Use the -w (--wrap) flag to return a reversible wrapped secret
$ redactr unredact -w "~~redacted-aes:JOf+CmAfgyCSbesz6zstfUx7gHIuJ/JMeyyf8UqCGvkxjkc=~~"
~~redact:hunter2~~
Hashicorp Vault

Secrets may be stored in a Hashicorp Vault instance.

The vault adapter uses the vault CLI's standard environment variables (see: https://www.vaultproject.io/docs/commands/#environment-variables)

Assuming vault has been appropriately configured, it can be used like:

$ redactr redact "~~redact-vault:/dev#my_password#hunter2~~"
vault~~/dev#my_password

$ redactr unredact "~~redacted-vault:/dev#my_password~~"
hunter2

# Use the -w (--wrap) flag to return a reversible wrapped secret
$ redactr unredact -w "~~redacted-vault:/dev#my_password~~"
~~redact-vault:/dev#my_password#hunter2~~

Documentation

Index

Constants

View Source
const (
	DoNothing = OnEnvChangeBehavior(iota) // default: do nothing
	Stop
	Restart
)

Available OnEnvChangeBehaviors

Variables

This section is empty.

Functions

func Exec added in v0.2.0

func Exec(runner Runner, opts ...ExecOption) error

Exec runs the Runner.

When called with the RestartIfEnvChanges or StopIfEnvChanges option, Exec will periodically re-evaluate the environment. If the environment has changed, Exec will restart or stop the runner as requested.

func WrapTokens

func WrapTokens(c *UnredactTokensConfig)

WrapTokens requests that unredacted secrets be wrapped in secret envelopes (ideally in the format understood by the corresponding redacter)

For example, a secret unredacter might try to unredact the token:

secret-redacted:zzz:secret-redacted

Assuming "zzz" is an redacted version of "hunter2", then a regular, unwrapped output would be:

hunter2

With the WrapTokens option, the output should become:

secret:hunter2:secret

This is helpful when a user wants to see a reversible output, such as when users want to rotate secrets or keys.

Types

type CompositeTokenRedacter added in v0.2.0

type CompositeTokenRedacter struct {
	Redacter Redacter
	Locator  TokenLocator
	Wrapper  TokenWrapper
}

A CompositeTokenRedacter looks for secret tokens within text, and redacts them

func (*CompositeTokenRedacter) RedactTokens added in v0.2.0

func (e *CompositeTokenRedacter) RedactTokens(s string) (string, error)

RedactTokens looks for secret tokens within text, and redacts them

type CompositeTokenUnredacter added in v0.2.0

type CompositeTokenUnredacter struct {
	Unredacter Unredacter
	Locator    TokenLocator
	Wrapper    TokenWrapper
}

A CompositeTokenUnredacter looks for redacted secret tokens within text, and unredacts them

func (*CompositeTokenUnredacter) UnredactTokens added in v0.2.0

func (d *CompositeTokenUnredacter) UnredactTokens(s string, opts ...UnredactTokensOption) (string, error)

UnredactTokens looks for redacted secret tokens within text, and unredacts them

type ExecConfig added in v0.2.0

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

ExecConfig is used to configure a call to Exec()

type ExecOption added in v0.2.0

type ExecOption func(*ExecConfig)

An ExecOption changes the way that Exec behaves

func RestartIfEnvChanges added in v0.2.0

func RestartIfEnvChanges(d time.Duration) ExecOption

RestartIfEnvChanges tells Exec to periodically re-check the configuration of the running command. If it changes, Exec will restart the command.

func StopIfEnvChanges added in v0.2.0

func StopIfEnvChanges(d time.Duration) ExecOption

StopIfEnvChanges tells Exec to periodically re-check the configuration of the running command. If it changes, Exec will stop the command.

type NewToolConfig

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

NewToolConfig is used to configure a Tool created by New()

type NewToolOption

type NewToolOption func(*NewToolConfig)

NewToolOption configures a Tool on a call to New()

func AESKey

func AESKey(key string) NewToolOption

AESKey sets the key used for AES encryption and decryption

type OnEnvChangeBehavior added in v0.2.0

type OnEnvChangeBehavior int8

OnEnvChangeBehavior determines the behavior of the Tool if it discovers that the environment has changed

type Redacter

type Redacter interface {
	Redact(string) (string, error)
}

A Redacter redacts secrets into a redacted form

type RegexTokenLocator

type RegexTokenLocator struct {
	RE *regexp.Regexp
}

A RegexTokenLocator locates tokens according to a regular expression (RE).

The regex should match a token envelope, and it should have one capturing group which captures the token payload. If the payload is the same as the envelope, the entire regex should be a capturing group.

func (*RegexTokenLocator) LocateTokens

func (l *RegexTokenLocator) LocateTokens(s string) ([]struct{ EnvelopeStart, PayloadStart, PayloadEnd, EnvelopeEnd int }, error)

LocateTokens locates all tokens according to the embedded regular expression

type Runner added in v0.2.0

type Runner interface {
	// Run runs the command. The runner should replace
	// relevant values with the Replacer. For example,
	// a command-line runner may replace values in
	// the environment.
	Run() error

	// HasConfigurationChanged should re-evaluate any
	// dynamic configuration, and return true if that
	// configuration differs from the configuration
	// that was used to Run().
	//
	// If the Runner is not running, it should
	// return false.
	HasConfigurationChanged() (bool, error)

	// Restart should restart the running runner.
	Restart()

	// Stop should stop the running Runner
	//
	Stop()
}

A Runner runs.

type StringWrapper

type StringWrapper struct {
	Before, After string
}

StringWrapper wraps tokens by putting strings before and after each token

func (*StringWrapper) WrapToken

func (w *StringWrapper) WrapToken(token, originalPayload, originalEnvelope string) string

WrapToken wraps the string with Before and After

type TokenLocator

type TokenLocator interface {
	LocateTokens(string) ([]struct{ EnvelopeStart, PayloadStart, PayloadEnd, EnvelopeEnd int }, error)
}

A TokenLocator locates tokens

Each token location is described by four indices, representing the start and end of the token (the envelope), and the start and end of the the token's payload.

type TokenRedacter

type TokenRedacter interface {
	RedactTokens(string) (string, error)
}

type TokenRedacterUnredacter

type TokenRedacterUnredacter interface {
	TokenRedacter
	TokenUnredacter
}

A TokenRedacterUnredacter can redact and unredact tokens

type TokenUnredacter

type TokenUnredacter interface {
	UnredactTokens(string, ...UnredactTokensOption) (string, error)
}

type TokenWrapper

type TokenWrapper interface {
	WrapToken(token, originalPayload, originalEnvelope string) string
}

A TokenWrapper wraps tokens

type Tool

type Tool struct {
	SecretUnredacter TokenUnredacter
	VaultUnredacter  TokenUnredacter

	SecretRedacter TokenRedacter
	VaultRedacter  TokenRedacter
}

A Tool can be used to redact and unredact secrets. If you want to use redactr as a library, you probably want to create and use a Tool.

func New

func New(opts ...NewToolOption) (*Tool, error)

New creates a new Tool

func (*Tool) Exec added in v0.2.0

func (t *Tool) Exec(name string, args []string, opts ...ExecOption) error

Exec executes a command. It acts like os.Exec, but with a couple of features that are helpful when working with redacted secrets:

  1. Before running the command, redacted secrets in the environment will be unredacted.

  2. When called with the RestartIfEnvChanges or StopIfEnvChanges option, Exec will periodically re-evaluate the environment. If the environment has changed, Exec will restart or stop the command as requested.

func (*Tool) RedactTokens

func (t *Tool) RedactTokens(s string) (string, error)

RedactTokens redacts all tokens in a string

func (*Tool) UnredactTokens

func (t *Tool) UnredactTokens(s string, opts ...UnredactTokensOption) (string, error)

UnredactTokens unredacts all tokens in a string

type UnredactTokensConfig

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

A UnredactTokensConfig configures a request to unredact tokens.

type UnredactTokensOption

type UnredactTokensOption func(*UnredactTokensConfig)

A UnredactTokensOption configures a request to unredact tokens.

type Unredacter

type Unredacter interface {
	Unredact(string) (string, error)
}

An Unredacter unredacts secrets

Directories

Path Synopsis
Package aes provides wrappers for AES-GCM encryption and decryption.
Package aes provides wrappers for AES-GCM encryption and decryption.
cli
fakes
Code generated by counterfeiter.
Code generated by counterfeiter.
cmd
fakes
Code generated by counterfeiter.
Code generated by counterfeiter.
Code generated by counterfeiter.
Code generated by counterfeiter.

Jump to

Keyboard shortcuts

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