Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions bash/habitual/secrets.functions
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# vim: et sr sw=4 ts=4 smartindent syntax=sh:
#
# @overview
# >
# > agnostic public interface for pluggable secrets management functions.
# >

# ... defines user-defined provider e.g. ssm - see [known_providers()](#known_providers)
SECRETS_PROVIDER="${SECRETS_PROVIDER,,}"

__SECRETS_HANDLERS_DIR="$(cd $(dirname $BASH_SOURCE) && pwd)/secrets"

# @desc Configures secrets management functions to use the expected provider.
#
# Pass a valid secrets provider. See [known_providers()](#known_providers) for getting the list.
# Sets `$SECRETS_PROVIDER` for the user.
set_secrets_provider() {
local p="$1"
__valid_provider "$p" || return 1
__run_init "$p" || return 1
export SECRETS_PROVIDER="$p"
return 0
}

__run_init() {
if declare -f "${p}_init" &>/dev/null
then
d "running init function ${p}_init()"
${p}_init || return 1
fi

return 0
}

__valid_provider() {
local p="$1" # ... provider name
local handler_file="$__SECRETS_HANDLERS_DIR/${p}.functions"

[[ -z "$p" ]] && red_e "expects a provider name for secrets management." && return 1

if ! known_providers | grep -Po "(\b$p\b)" >/dev/null
then
red_e "valid provider names are:\n$(known_providers)"
return 1
fi

# check file exists for sourcing
if [[ ! -r "$handler_file" ]]; then
red_e "readable handler file not found at $handler_file."
return 1
fi

! . $handler_file && red_e "unable to source $handler_file" && return 1

__imported_required_funcs "$p" || return 1

return 0
}

# @desc Prints supported secrets providers to STDOUT.
#
# We expect a file named after this provider that contains [required functions](#required_funcs).
#
# This is verified when [set_secrets_provider()](#set_secrets_provider) is run.
#
known_providers() {
cat << EOF | sort | uniq
credstash
ssm
EOF
}

__imported_required_funcs() {
local p="$1" # provider
local func="" failed="" rc=0

for func in $(required_funcs) ; do
if ! declare -f ${func} &>/dev/null
then
failed="${failed}function missing: ${func}\n"
rc=1
fi
done

if [[ $rc -eq 1 ]]; then
red_e "provider $p not implemented correctly:\n$failed"
fi

return $rc
}

# @desc Prints names of functions that must be defined.
# We expect them to be defined in the provider's handler file -
# the file that [set_secrets_provider()](#set_secrets_provider) sources.
#
required_funcs() {
cat <<EOF | sort | uniq
get_secret
put_secret
EOF
}

56 changes: 56 additions & 0 deletions bash/habitual/secrets.functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# habitual/secrets.functions

>
> agnostic public interface for pluggable secrets management functions.
>

* [GLOBALS](#globals)

* [FUNCTIONS](#functions)

---

# GLOBALS

* `$SECRETS_PROVIDER`: _... defines user-defined provider e.g. ssm - see [known\_providers()](#known\_providers)_
* reads env var `$SECRETS_PROVIDER,,`



# FUNCTIONS

* [set\_secrets\_provider()](#set_secrets_provider)
* [known\_providers()](#known_providers)
* [required\_funcs()](#required_funcs)

---

### set\_secrets\_provider()

Configures secrets management functions to use the expected provider.

Pass a valid secrets provider. See [known_providers()](#known_providers) for getting the list.
Sets `$SECRETS_PROVIDER` for the user.

---

### known\_providers()

Prints supported secrets providers to STDOUT.

We expect a file named after this provider that contains [required functions](#required_funcs).

This is verified when [set_secrets_provider()](#set_secrets_provider) is run.


---

### required\_funcs()

Prints names of functions that must be defined.
We expect them to be defined in the provider's handler file -
the file that [set_secrets_provider()](#set_secrets_provider) sources.


---

24 changes: 24 additions & 0 deletions bash/habitual/secrets/ssm.functions
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# vim: et sr sw=4 ts=4 smartindent syntax=sh:

# @overview
# >
# > Functions for interacting with AWS SSM parameter store secret values.

# @desc TODO ... we must check that the aws libs have been sourced.
# This function gets loaded automatically when
# [set_secrets_provider()](../secrets.functions.md#set_secrets_provider) is run.
ssm_init() {
# ... check that AWS libs are loaded
# ... check that aws cli exists on path
:
}

# @desc TODO ... for a given param name, get the secret
get_secret() {
:
}

# @desc TODO ... set a value for a given param name
put_secret() {
:
}
36 changes: 36 additions & 0 deletions bash/habitual/secrets/ssm.functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# habitual/secrets/ssm.functions

>
> Functions for interacting with AWS SSM parameter store secret values.

---


# FUNCTIONS

* [ssm\_init()](#ssm_init)
* [get\_secret()](#get_secret)
* [put\_secret()](#put_secret)

---

### ssm\_init()

TODO ... we must check that the aws libs have been sourced.
This function gets loaded automatically when
[set_secrets_provider()](../secrets.functions.md#set_secrets_provider) is run.

---

### get\_secret()

TODO ... for a given param name, get the secret

---

### put\_secret()

TODO ... set a value for a given param name

---

70 changes: 70 additions & 0 deletions bash/habitual/std.functions
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,76 @@ _semver_a_gt_b() {
[[ "$a" == "$b" ]] || [[ $(echo -e "$a\n$b" | sort -V | head -n 1) != "$a" ]]
}

# @desc Concatenates a multiline string, converting newlines to \n
#
# STDOUT: concatenated line
# *NOTE: the argument is double quoted if a variable, to preserve real newlines.*
#
# @example
# my_str="This is
# a multiline string"
# multiline_to_single "$my_str"
#
# # ... would print something like:
# # This is\na multiline string
#
multiline_to_single() {
local lines="$1"
if [[ -z "$line" ]]; then
red_e 'pass lines to combine with slash n e.g. single_line=$(multiline_to_single "$lines")'
return 1
fi
sed ':a;N;s/\n/\\n/;ta' <(echo "$lines")
}

# @desc Splits a string on '\n' to multiple lines with real newlines.
#
# STDOUT: Multiple lines
#
# These are an alternative to the `base64_encode` and
# `base64_decode` functions, for example, when base64 produces
# too long a string. Try storing an ssh key in AWS parameter store
# and see what I mean ...
#
# @example
# my_str="This will be\na multiline string"
# single_to_multiline "$my_str"
#
# # ... would print something like:
# # This will be
# # a multiline string
#
single_to_multiline() {
local line="$1"
[[ -z "$line" ]] && red_e 'pass a line to split on slash-n' && return 1
echo "$line" | sed -e 's/\\n/\n/g'
}

# @desc Encodes a string (or mulitline string) as Base64
#
# You can use this and `base64_decode` when you need to pass
# or store multiline strings as a single line.
#
# These are an alternative to the `single_to_multiline` and
# `multiline_to_single` functions when you wish to preserve existing
# '\n' instances in your strings, and not convert them to newlines
# or vice-versa.
#
base64_encode() {
local str="$1"
echo "$str" | base64 -w0
}

# @desc Decodes a base64 string
#
# You can use this and `base64_decode` when you need to pass
# or store multiline strings as a single line.
#
base64_decode() {
local str="$1"
echo "$str" | base64 -d
}

# @desc Exports $BUILD_URL if available from a number of possible sources.
#
# $BUILD_URL is a link to a CI/CD job's run.
Expand Down
77 changes: 77 additions & 0 deletions bash/habitual/std.functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
* [envsubst\_tokens\_list()](#envsubst_tokens_list)
* [random\_str()](#random_str)
* [semver\_a\_ge\_b()](#semver_a_ge_b)
* [multiline\_to\_single()](#multiline_to_single)
* [single\_to\_multiline()](#single_to_multiline)
* [base64\_encode()](#base64_encode)
* [base64\_decode()](#base64_decode)
* [export\_build\_url()](#export_build_url)
## LOG MESSAGE FUNCTIONS
---
Expand Down Expand Up @@ -222,6 +226,79 @@ semver_a_ge_b 0.99.0-beta V0.99.0-alpha # true (as beta beats alpha)
```


---

### multiline\_to\_single()

Concatenates a multiline string, converting newlines to \n

STDOUT: concatenated line
*NOTE: the argument is double quoted if a variable, to preserve real newlines.*

#### Example

```bash
my_str="This is
a multiline string"
multiline_to_single "$my_str"

# ... would print something like:
# This is\na multiline string

```


---

### single\_to\_multiline()

Splits a string on '\n' to multiple lines with real newlines.

STDOUT: Multiple lines

These are an alternative to the `base64_encode` and
`base64_decode` functions, for example, when base64 produces
too long a string. Try storing an ssh key in AWS parameter store
and see what I mean ...

#### Example

```bash
my_str="This will be\na multiline string"
single_to_multiline "$my_str"

# ... would print something like:
# This will be
# a multiline string

```


---

### base64\_encode()

Encodes a string (or mulitline string) as Base64

You can use this and `base64_decode` when you need to pass
or store multiline strings as a single line.

These are an alternative to the `single_to_multiline` and
`multiline_to_single` functions when you wish to preserve existing
'\n' instances in your strings, and not convert them to newlines
or vice-versa.


---

### base64\_decode()

Decodes a base64 string

You can use this and `base64_decode` when you need to pass
or store multiline strings as a single line.


---

### export\_build\_url()
Expand Down