1
0
mirror of https://github.com/getsops/sops.git synced 2026-02-05 12:45:21 +01:00

Added all-in-one example

This commit is contained in:
Todd Wolfson
2016-02-24 22:02:22 -06:00
parent 7cb2f51b0d
commit e3a4dd96fb
8 changed files with 192 additions and 0 deletions

1
examples/all_in_one/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
config/secret.json

View File

@@ -0,0 +1,81 @@
All-in-one example
==================
This directory is an example configuration for SOPS inside of a project. We will cover the files used and relevant scripts for developers.
This example is optimized for saving developer time by storing all secrets in a single file (e.g. ``secret.enc.json``).
One downside is any configurations which should be stored side by side might not be.
Getting started
---------------
To use this example, run the following:
.. code:: bash
# From the `sops` root directory
# Import the test key
gpg --import tests/sops_functional_tests_key.asc
# Navigate to our example directory
cd examples/all_in_one
# Decrypt our secrets
bin/decrypt-config.sh
# Optionally edit a secret
# bin/edit-secret.sh config/secret.enc.json
# Run a script that uses our decrypted secrets
python main.py
Storage
-------
In both development and production, we will be storing the secrets file unencrypted on disk. This is for a few reasons:
- Can't store file in an encrypted manner because we would need to know the secret to decode it
- Loading it into memory at boot is impractical
- Requires reimplementing SOPS' decryption logic to multiple languages which increases chance of human error which is bad for security
- If someone uses an automatic process reloader during development, then it could get expensive with AWS
- We could cache the results from AWS but those secrets would wind up being stored on disk
As peace of mind, think about this:
- Unencrypted on disk is fine because if the attacker ever gains access to the server, then they can run ``sops --decrypt`` as well.
Files
-----
- ``bin/decrypt-config.sh`` - Script to decrypt secret file
- ``bin/edit-config-file.sh`` - Script to edit a secret file and then decrypt it
- ``config/secret.enc.json`` - Catch-all file containing our secrets
- ``config/secret.json`` - Decrypted catch-all secrets file
- ``config/static.py`` - Configuration file which imports secrets
- ``.gitignore`` - Ignore file for decrypted secret file
- ``main.py`` - Example script
Usage
-----
Development
~~~~~~~~~~~
For development, each developer must have access to the PGP/KMS keys. This means:
- If we are using PGP, then each developer must have the private key installed on their local machine
- If we are using KMS, then each developer must have AWS access to the appropriate key
Testing
~~~~~~~
For testing in a public CI, we can copy ``secret.enc.json`` to ``secret.json``. This will represent the same structure as ``secret.enc.json`` with an additional ``sops`` key but not reveal any secret information.
..
For convenience, we can run ``CONFIG_COPY_ONLY=TRUE bin/decrypt-config.sh`` which will use ``cp`` rather than ``sops --decrypt``.
For testing in a private CI where we need private information, see the `Production instructions <#production>`_.
Production
~~~~~~~~~~
For production, we have a few options:
- Build an archive (e.g. ``.tar.gz``) in a private CI which contains the secrets and deploy our service via the archive
- Install PGP private key/KMS credentials on production machine, decrypt secrets during deployment process on production machine

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Exit on first error
set -e
# Define our secret files
secret_files="secret.enc.json"
# For each of our files in our encrypted config
for file in $secret_files; do
# Determine src and target for our file
src_file="config/$file"
target_file="$(echo "config/$file" | sed -E "s/.enc.json/.json/")"
# If we only want to copy, then perform a copy
# DEV: We allow `CONFIG_COPY_ONLY` to handle tests in Travis CI
if test "$CONFIG_COPY_ONLY" = "TRUE"; then
cp "$src_file" "$target_file"
# Otherwise, decrypt it
else
sops --decrypt "$src_file" > "$target_file"
fi
done

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Exit on first error
set -e
# Define our secret files
secret_files="secret.enc.json"
# Look up our file
filepath="$1"
if test "$filepath" = ""; then
echo "Expected \`filepath\` but received nothing" 1>&2
echo "Usage: $0 <filepath>" 1>&2
exit 1
fi
# If our file is a secret
filename="$(basename "$filepath")"
if echo "$secret_files" | grep "$filename"; then
# Load it into SOPS and run our sync script
sops "$filepath"
bin/decrypt-config.sh
# Otherwise (it's a normal file)
else
# Resolve our editor via `sops` logic
editor="$EDITOR"
if test "$editor" = ""; then
editor="$(which vim nano | head -n 1)"
fi
if test "$editor" = ""; then
echo "Expected \`EDITOR\` environment variable to be defined but it was not" 1>&2
exit 1
fi
# Edit our file
"$editor" "$filepath"
fi

View File

View File

@@ -0,0 +1,22 @@
{
"github_oauth_token": "ENC[AES256_GCM,data:B2/q7WKJRqAUf4vvh8o=,iv:WpyxvYMHVMz4UvX2xZf79jaQYTSdepF96k87nMcuEro=,tag:FIqBSEuhh14JyjkGlW4hvw==,type:str]",
"sops": {
"lastmodified": "2016-02-12T05:14:20Z",
"attention": "This section contains key material that should only be modified with extra care. See `sops -h`.",
"unencrypted_suffix": "_unencrypted",
"mac": "ENC[AES256_GCM,data:In6U2fZvaX2JI9jSnNYwWEYAuyh5YPUwCaAV5qeWON47zxxy4f2ad9gNwqxS4WsA7jf/DsYXv73OyXTqWV0sb8CBtzyVjzm9tgIcwNkKncROXY2njT+Y1LZAdIDPnz1Rw9PHOfZwHM8xxlly78uK/TuzX0nXADBtkIAAksVa3xw=,iv:/GjlxMSNouhw8yqsAG+bfGIz+YWz+/LNfrOHh/LC4OU=,tag:/5I+0uEWQ3hIL9ztuPQZwA==,type:str]",
"version": 1.6,
"kms": [
{
"arn": ""
}
],
"pgp": [
{
"fp": "1022470DE3F0BC54BC6AB62DE05550BC07FB1A0A",
"created_at": "2016-02-12T05:14:20Z",
"enc": "-----BEGIN PGP MESSAGE-----\nVersion: GnuPG v1\n\nhIwDEEVDpnzXnMABA/9hQVFyHXnNCnE0YIcXvar4YtFyRNnuV5zTaQskRqPYS14z\nPkqUpx03PVsT4c84YLx3bAu9OM0so8fsXAW7+YpX5A1ZChWpy0Qt7lg6k/4qyUSl\nMO5x+4ZdU5C866no0Q3UHrBy0oxORYUwbKsWU8IMSNWuSXGcqRsU0nyschvhb9Je\nARNsbbGsL2qeaYqjTwD3p3awkef2voVwYGTuSbvKcEfb5X1JrWrX1Igk8wwCe/uw\nlB2SXpk1bQ16ZfsT39+bOaeu6v8mREHG+KKk3k7ddFmML5TbPYqSme7BcW1IQA==\n=c6L/\n-----END PGP MESSAGE-----\n"
}
]
}
}

View File

@@ -0,0 +1,12 @@
# Load in our dependencies
import json
# Load in our secrets
with open('config/secret.json', 'r') as file:
secret = json.loads(file.read())
# Define our configuration
common = {
'github_oauth_token': secret['github_oauth_token'],
'port': 8080,
}

View File

@@ -0,0 +1,18 @@
# Load in our dependencies
from __future__ import absolute_import
from config.static import common
# Define our main function
def main():
# Output our configuration
print('Configuration')
print('-------------')
for key in common:
# Example: `port: "8080"`
print('{key}: "{val}"'.format(key=key, val=common[key]))
# If this script is being invoked directly, then run our main function
if __name__ == '__main__':
main()