logfusc

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 13, 2023 License: MIT Imports: 3 Imported by: 0

README

logfusc – surefire secret redaction for logs and traces

Instrument your codebase with confidence. logfusc is a Go library that makes redacting sensitive data from logs and traces simple. Stop scrubbing logs in the aftermath of preventable human errors. Make your secrets unloggable.

A family of gophers riding a log down a river

logfusc.Secret

logfusc.Secret is a generic wrapper for any type that you want to redact from logs, traces and other outputs.

Secret implements fmt.Stringer and fmt.GoStringer, so no matter how hard you try to format it, it doesn't give up its secret.

password := "do not log!"
secret := logfusc.NewSecret(password)

fmt.Printf("%s\n", secret)
// => logfusc.Secret[string]{REDACTED}

fmt.Printf("%q\n", secret)
// => "logfusc.Secret[string]{REDACTED}"

fmt.Printf("%v\n", secret)
// => "logfusc.Secret[string]{REDACTED}"

fmt.Printf("%+v\n", secret)
// => "logfusc.Secret[string]{REDACTED}"

fmt.Printf("%#v\n", secret)
// => "logfusc.Secret[string]{REDACTED}"

fmt.Printf("%x\n", secret)
// => 6c6f67667573632e5365637265745b737472696e675d7b52454441435445447d == logfusc.Secret[string]{REDACTED}
Log anything, anywhere

logfusc.Secret redacts your secrets when marshaled to a variety of formats, so you can pass complete structs to your logger without worrying about leaking sensitive data. No more manual redaction. No configuration. No leaks.

type Universe struct {
    SecretOfLife logfusc.Secret[int] `json:"secret_of_life"`
}

func main() {
  universe := Universe{
      SecretOfLife: logfusc.NewSecret(42),
  }

  b, _ := json.Marshal(universe)

  log.Println(string(b))
}

// => {"name":"alice","secret_of_life":"logfusc.Secret[int]{REDACTED}"}

So far, Secret satisfies:

  • json.Marshaler (tested with both encoding/json and json-iterator)
  • More coming soon! Too slow for you? Why not contribute?
Decode directly to logfusc.Secret

Protect secrets at the boundaries of your service by decoding them directly into logfusc.Secret.

type RegisterRequest struct {
  Email string `json:"email"`
  Password logfusc.Secret[string] `json:"password"`
}

func Register(w http.ResponseWriter, r *http.Request) {
  var req RegisterRequest
  _ = json.NewDecoder(r.Body).Decode(&req)
  fmt.Println(req.Password)
  fmt.Println(req.Password.Expose())
}

// => logfusc.Secret[string]{REDACTED}
//    password

So far, Secret satisfies:

  • json.Unmarshaler
  • More coming soon! Too slow for you? Why not contribute?
Use secrets with intention

Secret encourages you to log often and trace everything in the knowledge that your secrets are safe. That doesn't stop you working with sensitive data, but you have to do it deliberately.

secret := logfusc.NewSecret("PEM string")
log.Println(secret.Expose())

// => PEM string

Compatibility

logfusc.Secret should work as described with all sane logging libraries.

"Should" because, in Go, you can technically access the private fields of a struct using a combination of the reflect and unsafe packages. If your logger is doing this, you need a new one.

For your peace of mind, logfusc.Secret has been explicitly tested for compatibility with the following loggers:

  • log
  • logrus
  • zap
  • zerolog
  • More compatibility tests coming soon! Too slow for you? Why not contribute?

Documentation

Overview

Package logfusc provides a generic Secret type that obsufcates all string representations of its wrapped value, preventing sensitive data from being inadvertently written to output.

It is a lightweight approach to redacting secrets and personally identifiable information from logs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Secret

type Secret[T any] struct {
	// contains filtered or unexported fields
}

Secret wraps a sensitive value, preventing it from being inadvertently written to output. This insures against human error leading to runtime data leaks. It is not a secrets manager, and has no cryptographic components.

Satisfies fmt.Stringer, fmt.GoStringer, encoding/json.Marshaler and encoding/json.Unmarshaler.

Secret is NOT thread-safe, but references to the wrapped value should not be retained after instantiation, so this shouldn't be a problem.

func NewSecret

func NewSecret[T any](value T) Secret[T]

NewSecret returns a new Secret containing an instance of T. It is recommended to pass a value type, not a pointer, since any retained references to the wrapped value won't benefit from Secret's protection.

func (Secret[T]) Expose

func (s Secret[T]) Expose() T

Expose returns the wrapped secret for use, at which point it is vulnerable to leaking to output.

func (Secret[_]) GoString

func (s Secret[_]) GoString() string

GoString satisfies `fmt.GoStringer`, which controls formatting in response to the `%#v` directive, preventing the inner value from being printed.

func (Secret[_]) MarshalJSON

func (s Secret[_]) MarshalJSON() ([]byte, error)

MarshalJSON satisfies encoding/json.Marshaler, preventing the inner value from being inadvertently marshaled to JSON (e.g. as part of a structured log entry).

If the wrapped secret that must be marshaled for transport, call Secret.Expose to unwrap it.

func (Secret[_]) String

func (s Secret[_]) String() string

String renders the Secret and its contents in the format `REDACTED T`, where T is the type of the obfuscated value.

func (*Secret[T]) UnmarshalJSON

func (s *Secret[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON satisfies encoding/json.Unmarshaler, allowing a sensitive value to be unmarshaled directly into a Secret.

If `data` cannot be unmarshaled into type T, an UnmarshalError is returned.

type UnmarshalError

type UnmarshalError[T any] struct {
	// contains filtered or unexported fields
}

UnmarshalError is returned by [Secret.Unmarshal] if the provided JSON cannot be unmarshaled into the the type T wrapped by a Secret. It is returned instead of the standard encoding/json errors to prevent leakage of the secret (however malformed).

func (*UnmarshalError[T]) Error

func (e *UnmarshalError[T]) Error() string

Jump to

Keyboard shortcuts

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