View Source RedactEx (RedactEx v0.1.6)
RedactEx provides protocols and derivation utilities to work with sensitive data that should be redacted in logs and external facing tools
RedactEx.Redactor
module gives you automagical generation of redacting functions under a desired module namespaceRedactEx.Redactable
is the protocol for which implementation and derivation should be created to ensure the best possible practices in your codebase
protect-your-data
Protect your data
RedactEx usual protection consists in two or more steps:
generate-your-redactor-functions
Generate your redactor functions
You can generate functions to redact your specific data using RedactEx.Redactor
module.
iex> defmodule MyApp.Redacting do
...> @moduledoc false
...> use RedactEx.Redactor, redactors: [
...> {"redact_three", length: 3, algorithm: :simple},
...> {"redact", lengths: 1..3, algorithm: :simple}
...> ]
...> end
This will generate optimized functions and/or functions adopting the standards and algorithms defined in this library. In particular:
redact_three/1
will be created with an optimized match for strings of length 3 and a non optimized fallback function for strings with generic lengthredact/1
will be created with three optimized match for strings of lengths 1, 2 and 3 and a non optimized fallback function for strings with generic length
protect-your-structs
Protect your structs
The recommended way of protecting your structs is
1-derive-or-implement-redactex-redactable
1. Derive or implement RedactEx.Redactable
You can use the @derive
macro from the RedactEx.Redactable
protocol,
configured based on your needs and optionally using functions from a module generated with
RedactEx.Redactor
helpers, or manually define an implementation of choice, e.g.
iex> defmodule MyRedactorModule do
...> def redact_function_one(_), do: "(redacted1)"
...> def redact_function_two(_), do: "(redacted2)"
...> end
...> defmodule MyApp.RedactStruct do
...> @derive {RedactEx.Redactable,
...> fields: [
...> myfield1: {MyRedactorModule, :redact_function_one},
...> myfield2: {MyRedactorModule, :redact_function_two},
...> ]}
...> defstruct [:myfield1, :myfield2]
...> end
or
iex> defmodule MyApp.OtherRedactStruct do
...> defstruct [:myfield1, :myfield2]
...> end
...> defimpl RedactEx.Redactable, for: MyApp.OtherRedactStruct do
...> def redact(_value), do: %MyApp.OtherRedactStruct{myfield1: "(redacted)", myfield2: "(redacted)"}
...> end
2-use-inspect-protocol-at-your-advantage
2. Use inspect
protocol at your advantage
No strategy can eliminate the risk of leaking sensitive data with code only.
Our suggested approach is to derive also the inspect protocol and use it for your struct whenever you log or send data to external systems, e.g.
iex> defimpl Inspect,
...> for: MyApp.OtherRedactStruct do
...> alias MyApp.OtherRedactStruct
...> alias RedactEx.Redactable
...>
...> @spec inspect(OtherRedactStruct.t(), Inspect.Opts.t()) :: Inspect.Algebra.t()
...> def inspect(input, opts) do
...> input
...> |> Redactable.redact()
...> |> Inspect.Any.inspect(opts)
...> end
...> end
Another strategy could be to directly call RedactEx.Redactable.redact/1
on structs when logging, but using
inspect
seems to us more natural and idiomatic.
Another strategy could be to redact
/inspect
your data directly in a custom Logger backend, or whatever the system
used for exporting potentially sensitive data.