All Projects → gordalina → Hush

gordalina / Hush

Licence: other
Runtime configuration loader extensible with providers

Programming Languages

elixir
2628 projects

Labels

Projects that are alternatives of or similar to Hush

Terracognita
Reads from existing Cloud Providers (reverse Terraform) and generates your infrastructure as code on Terraform configuration
Stars: ✭ 452 (+564.71%)
Mutual labels:  aws, gcp
Opshell
DevOps Toolkit for Every Cloud on Every Cloud
Stars: ✭ 19 (-72.06%)
Mutual labels:  aws, gcp
Gbt
Highly configurable prompt builder for Bash, ZSH and PowerShell written in Go.
Stars: ✭ 457 (+572.06%)
Mutual labels:  aws, gcp
Terratag
Terratag is a CLI tool that enables users of Terraform to automatically create and maintain tags across their entire set of AWS, Azure, and GCP resources
Stars: ✭ 385 (+466.18%)
Mutual labels:  aws, gcp
Go Cloud
The Go Cloud Development Kit (Go CDK): A library and tools for open cloud development in Go.
Stars: ✭ 8,124 (+11847.06%)
Mutual labels:  aws, gcp
External Dns
Configure external DNS servers (AWS Route53, Google CloudDNS and others) for Kubernetes Ingresses and Services
Stars: ✭ 4,749 (+6883.82%)
Mutual labels:  aws, gcp
Porter
Kubernetes powered PaaS that runs in your own cloud.
Stars: ✭ 498 (+632.35%)
Mutual labels:  aws, gcp
Mkit
MKIT is a Managed Kubernetes Inspection Tool that validates several common security-related configuration settings of managed Kubernetes cluster objects and the workloads/resources running inside the cluster.
Stars: ✭ 330 (+385.29%)
Mutual labels:  aws, gcp
Ethereum Etl
Python scripts for ETL (extract, transform and load) jobs for Ethereum blocks, transactions, ERC20 / ERC721 tokens, transfers, receipts, logs, contracts, internal transactions. Data is available in Google BigQuery https://goo.gl/oY5BCQ
Stars: ✭ 956 (+1305.88%)
Mutual labels:  aws, gcp
Cloudguardiaas
Check Point CloudGuard Network Security repository containing solution templates, Terraform templates, tools and scripts for deploying and configuring CloudGuard Network Security products.
Stars: ✭ 27 (-60.29%)
Mutual labels:  aws, gcp
Rump
Hot sync two Redis servers using dumps.
Stars: ✭ 382 (+461.76%)
Mutual labels:  aws, gcp
Examples
Infrastructure, containers, and serverless apps to AWS, Azure, GCP, and Kubernetes... all deployed with Pulumi
Stars: ✭ 1,085 (+1495.59%)
Mutual labels:  aws, gcp
Cloud Custodian
Rules engine for cloud security, cost optimization, and governance, DSL in yaml for policies to query, filter, and take actions on resources
Stars: ✭ 3,926 (+5673.53%)
Mutual labels:  aws, gcp
Devops Python Tools
80+ DevOps & Data CLI Tools - AWS, GCP, GCF Python Cloud Function, Log Anonymizer, Spark, Hadoop, HBase, Hive, Impala, Linux, Docker, Spark Data Converters & Validators (Avro/Parquet/JSON/CSV/INI/XML/YAML), Travis CI, AWS CloudFormation, Elasticsearch, Solr etc.
Stars: ✭ 406 (+497.06%)
Mutual labels:  aws, gcp
Rpc Websockets
JSON-RPC 2.0 implementation over WebSockets for Node.js and JavaScript/TypeScript
Stars: ✭ 344 (+405.88%)
Mutual labels:  aws, gcp
Terraformer
CLI tool to generate terraform files from existing infrastructure (reverse Terraform). Infrastructure to Code
Stars: ✭ 6,316 (+9188.24%)
Mutual labels:  aws, gcp
Docker Android
Android in docker solution with noVNC supported and video recording
Stars: ✭ 4,042 (+5844.12%)
Mutual labels:  aws, gcp
Grant
OAuth Proxy
Stars: ✭ 3,509 (+5060.29%)
Mutual labels:  aws, gcp
Offensive Terraform.github.io
Offensive Terraform Website
Stars: ✭ 25 (-63.24%)
Mutual labels:  aws, gcp
Kubernetes Guides
Crosswalk Playbooks and Code for Teams to Manage Kubernetes in Production
Stars: ✭ 51 (-25%)
Mutual labels:  aws, gcp

Hush

Build Status Coverage Status hex.pm version

Hush is designed to help developers configure their applications at runtime and in release mode, retrieving configuration from multiple providers, without having to depend on secret files or hardcoded configuration.

Documentation can be found at https://hexdocs.pm/hush.

Overview

Hush can be used to inject configuration that is not known at compile time, such as environmental variables (e.g.: Heroku's PORT env var), sensitive credentials such as your database password, or any other information you need.

# config/prod.exs
alias Hush.Provider.{AwsSecretsManager, GcpSecretManager,SystemEnvironment}

config :app, Web.Endpoint,
  http: [port: {:hush, SystemEnvironment, "PORT", [cast: :integer]}]

config :app, App.Repo,
  password: {:hush, GcpSecretManager, "CLOUDSQL_PASSWORD"}

config :app, App.RedshiftRepo,
  password: {:hush, AwsSecretsManager, "REDSHIFT_PASSWORD"}

Hush resolves configuration from using providers, it ships with a SystemEnvironment provider which reads environmental variables, but multiple providers exist. You can also write your own easily.

Provider Description Link
SystemEnvironment Reads environmental variables.
AwsSecretsManager Load secrets from AWS Secrets Manager. GitHub
GcpSecretManager Load secrets from Google Cloud Secret Manager. GitHub

Installation

Add hush to your list of dependencies in mix.exs:

def deps do
  [
    {:hush, "~> 0.4.0"}
  ]
end

Run mix deps.get to install it.

Some providers may need to initialize applications to function correctly. The providers will be explicit about whether they need to be loaded at startup or not. GcpSecretsManager unlike SystemEnvironment is one such example. To load the provider you need to configure it like so. Note: SystemEnvironment does not need to be loaded at startup.

# config/config.exs

config :hush,
  providers: [
    GcpSecretsManager
  ]

Usage

Hush can be loaded in two ways, at runtime in your application, or as a Config.Provider in release mode. A sample app has been written so you can see how it's configured.

Loading at runtime

# application.ex

def start(_type, _args) do
  Hush.resolve!()
end

Loading via in release mode

To load hush as a config provider, you need to define in your releases in mix.exs.

def project do
  [
    # ...
    releases: [
      app: [
        config_providers: [{Hush.ConfigProvider, nil}]
      ]
    ]
  ]
  end

If you are using Hush in runtime and release mode, make sure to only resolve configuration in non release mode:

# application.ex

def start(_, _) do
  unless Hush.release_mode?(), do: Hush.resolve!()
end

Configuration format

Hush will resolve any tuple in the following format into a value.

{:hush, Hush.Provider, "key", options \\ []}
  • Hush.Provider can be any module that implements its behaviour.
  • "key" is passed to the provider to retrieve the data.
  • options is a a Keyword list with the following properties:
    • default: any() - If the provider can't find the value, hush will return this value
    • optional: boolean() - By default, Hush will raise an error if it cannot find a value and there's no default, unless you mark it as optional.
    • cast: :string | :atom | :charlist | :float | :integer | :boolean | :module - You can ask Hush to cast the value to a Elixir native type.
    • to_file: string() - Write the data to the path give in to_file() and return the path.

After Hush resolves a value it runs them through Transfomers.

Examples

By default if a given key is not found by the provider, Hush will raise an error. To prevent this, provide a default or optional: true in the options component of the tuple.

Default

# config/config.exs
alias Hush.Provider.SystemEnvironment

config :app,
  url: {:hush, SystemEnvironment, "HOST", default: "example.domain"}

# result without environmental variable
assert "example.domain" == Application.get_env(:app, :url)

# result with env HOST=production.domain
assert "production.domain" == Application.get_env(:app, :url)

Casting

Here we are reading the PORT environmental variable, casting it to an integer and returning it

# config/config.exs
alias Hush.Provider.SystemEnvironment

config :app,
  port: {:hush, SystemEnvironment, "PORT", cast: :integer, default: 4000}

# result without environmental variable
assert 4000 == Application.get_env(:app, :url)

# result with env PORT=443
assert 443 == Application.get_env(:app, :url)

Optional

# config/dev.exs
alias Hush.Provider.SystemEnvironment

config :app,
  can_be_nil: {:hush, SystemEnvironment, "KEY", optional: true}

# result without environmental variable
assert nil == Application.get_env(:app, :can_be_nil)

# result with env KEY="is not nil"
assert "is not nil" == Application.get_env(:app, :can_be_nil)

Transfomers

By default Hush ships with the following transformers:

  • Hush.Transfomer.Cast: Takes an argument cast and converts a value into a specific type.
  • Hush.Transfomer.ToFile: Takes an arugment to_file and outputs the value into the path provided.

It is possible to add more transformers by the following configuration:

# config/prod.exs

alias Hush.Provider.SystemEnvironment

config :hush,
  transfomers: [
    App.Hush.JsonToMapTransfomer
  ]

config :app,
  allowed_urls: {:hush, SystemEnvironment, "alloweds_urls", [json: true]}

It is also possible to override the transforms Hush will process, and the order they will execute in. See below for more information.

Writing your own transfomer

The currently shipped transfomers are good examples on how to implement transformers.

Transformers are executed in order they are defined, first is Cast, next is ToFile and then the ones configured by you, e.g.:

# config/prod.exs

config :hush,
  transformers: [
    App.Hush.JsonTransformer
  ]

Lets dissect a transformer as an example. A transformer has to implement the Hush.Transformer behaviour, and as such it has to implement the key/0 and transform/2 functions.

A transformer is going to be executed if a configuration tuple requests it by passing the value of key/0 into its options. An example is seeing the json parameter being passed into the value configuration. Hush will process any transformers in which their key/0 function returns :json.

Once a configuration tuple requests a transfomer, a function transform/2 is called, where the first argument is what is passed as a value of the key/0 (in the example below it would be :abort_on_failure), and the second argument would be the current value returned by the provider transformed by any previous transformers.

# config/prod.exs

config :app,
  value: {:hush, SystemEnvironment, "key", [json: :abort_on_failure]}
# lib/app/hush/JsonTransformer.ex

defmodule App.Hush.JsonTransformer do
  @behaviour Hush.Transformer

  @impl true
  @spec key() :: :json
  def key(), do :json

  @impl true
  @spec transform(config :: any(), value :: any()) :: {:ok, any()} | {:error, String.t()}
  def transform(config, value) do
    try do
      Jason.decode!(value)
    rescue
      error ->
        case config do
          :abort_on_failure ->
            {:error, "Couldn't convert #{value} to json: #{error.message}"}
          _ ->
            {:ok, nil}
        end
    end
  end
end

Overriding Transformers

The following example woud take a value passed as an environment variable ALLOWED_URLS='["http://example.com"]' into a file named /tmp/urls.json with the contents ["https://example.com"], all due to the order in which the transformers are executed and the fact that override_transformers is true.

# config/prod.exs

config :hush,
  override_transformers: true,
  transformers: [
    Hush.Transformer.Cast,
    App.Hush.HttpToHttpsTransformer,
    App.Hush.JsonTransformer,
    Hush.Transformer.ToFile,
  ]

config :app,
  value: {:hush, SystemEnvironment, "ALLOWED_URLS", [http_to_https: true, json: true, to_file: "/tmp/urls.json" ]}
# lib/app/hush/HttpToHttpsTransfomer.ex

defmodule App.HttpToHttpsTransfomer do
  @behaviour Hush.Transformer

  @impl true
  @spec key() :: :http_to_https
  def key(), do :http_to_https

  @impl true
  @spec transform(config :: any(), value :: any()) :: {:ok, any()} | {:error, String.t()}
  def transfomer(_config, value) do
    {:ok, Enum.map(value, &http_to_https(&2))}
  end

  def http_to_https(value) do
    Regex.replace(~r/^http:/, value, "https:")
  end
end

Providers

Writing your own provider

An example provider is Hush.Provider.SystemEnvironment, which reads environmental variables at runtime. Here's an example of how that provider would look in a app configuration.

  alias Hush.Provider.SystemEnvironment

  config :app, Web.Endpoint,
    http: [port: {:hush, SystemEnvironment, "PORT", [cast: :integer, default: 4000]}]

This behaviour expects two functions:

  • load(config :: Keyword.t()) :: :ok | {:error, any()}
    

    This function is called at startup time, here you can perform any initialization you need, such as loading applications that you depend on.

  • fetch(key :: String.t()) :: {:ok, String.t()} | {:error, :not_found} | {:error, any()}
    

    This function is called when hush is resolving a key with you provider. Ensure that you implement a {:error, :not_found} if the value can't be found as hush will replace with it a default one if the user providede one.

    Note: All values are required by default, so if the user did not supply a default or made it optional, hush will trigger the error, you don't need to handle that use-case.

To implement that provider we can use the following code.

  defmodule Hush.Provider.SystemEnvironment do
  @moduledoc """
  Provider to resolve runtime environmental variables
  """

  @behaviour Hush.Provider

  @impl Hush.Provider
  @spec load(config :: Keyword.t()) :: :ok | {:error, any()}
  def load(_config), do: :ok

  @impl Hush.Provider
  @spec fetch(key :: String.t()) :: {:ok, String.t()} | {:error, :not_found}
  def fetch(key) do
    case System.get_env(key) do
      nil -> {:error, :not_found}
      value -> {:ok, value}
    end
  end
end

License

Hush is released under the Apache License 2.0 - see the LICENSE file.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].