Skip to content
Snippets Groups Projects
Unverified Commit 271cc8ec authored by Max Adamo's avatar Max Adamo
Browse files

Initial commit

parents
Branches
Tags
No related merge requests found
.*.sw[op]
.DS_Store
acme-downloader
\ No newline at end of file
This diff is collapsed.
# vault-secrets-shuffle
1. [configuration](#configuration)
1. [usage](#usage)
1. [compatibility](#compatibility)
1. [build](#build)
1. [notes](#notes)
Fetches nodes definitions from PuppetDB, generate random secrets for each host and store them to Vault.
It is meant to be used in conjunction with [hiera_vault](https://github.com/petems/petems-hiera_vault)
## configuration
you have:
- a kv v2 store on Vault
- puppet Hiera connected to Vault through [hiera_vault](https://github.com/petems/petems-hiera_vault) and your lookups include certnames/fqdn
- a configuration file with one `vault` section as following (beware of file permissions):
```ini
[vault]
# Vault parameters
vault_token = xxxxxxxxxxx
vault_ssl = true
vault_host = vault.yourdomain.org
vault_port = 443
vault_path = test/toast
vault_keyname = vault_root_password
# PuppetDB parameters
puppetdb_host = puppetdb.yourdomain.org
puppetdb_port = 8080
# Password properties
pass_lenght = 10
min_digits = 2
max_digits = 6
min_symbols = 0
max_symbols = 0
```
## usage
you can run the tool with `--help` to check all options:
```bash
vault-secrets-shuffle --help
Vault Secrets Shuffler:
- iterates all VMs registered in PuppetDB
- generate generate random secrets different for each host
- upload the secrets to vault.
Usage:
vault-secrets-shuffle --config=CONFIG [--kv=kv] [--write=WRITE] [--debug]
vault-secrets-shuffle -v | --version
vault-secrets-shuffle -b | --build
vault-secrets-shuffle -h | --help
Options:
-h --help Show this screen
-c --config=CONFIG Config file
-w --write=WRITE Output file (OPTIONAL)
-k --kv=kv Keystore Version. [default: 2]
-d --debug Print password and full key path (OPTIONAL)
-v --version Print version exit
-b --build Print version and build information and exit
```
or you can simply run:
```bash
vault-secrets-shuffle --config /path/to/file.conf
```
## compatibility
tested against:
- puppetdb 6.2
- vault 1.0.2
## build
you can use `build.sh` from this repo
## notes
Some change is already in the work on [petems/petems-hiera_vault#43](https://github.com/petems/petems-hiera_vault/pull/43)
These changes will allow to use Kv v2, which is safer to use (as it has password history)
build.sh 0 → 100755
#!/bin/bash
#if ! which upx &>/dev/null; then
# echo "please download upx here https://github.com/upx/upx/releases"
# echo "and store the executable within your \$PATH"
# exit
#fi
BIN_NAME=acme-downloader
PATH=$PATH:$(go env GOPATH)/bin
GOPATH=$(go env GOPATH)
export BIN_NAME PATH GOPATH
#LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
#PROG_VERSION=$(echo $LATEST_TAG | sed -e 's/^v//')
PROG_VERSION="1.0"
BUILDTIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
rm -rf ${GOPATH}/src/github.com/maxadamo/${BIN_NAME}
#go get -ldflags "-s -w -X main.appVersion=${PROG_VERSION} -X main.buildTime=${BUILDTIME}" github.com/maxadamo/${BIN_NAME}
go get -ldflags "-s -w -X main.appVersion=${PROG_VERSION} -X main.buildTime=${BUILDTIME}" .
# upx --brute ${GOPATH}/bin/${BIN_NAME}
if [ $? -gt 0 ]; then
echo -e "\nthere was an error while compiling the code\n"
exit
fi
echo -e "\nthe binary was compiled and it is avilable as:\n - ${GOPATH}/bin/${BIN_NAME}\n"
main.go 0 → 100644
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/docopt/docopt-go"
"github.com/go-ini/ini"
"github.com/tidwall/gjson"
)
var (
appVersion string
buildTime string
CertBase string
KeyBase string
GroupName string
RedisBaseURL string
VaultBaseURL string
certificateDestination string
fullchainDestination string
keyDestination string
caDestination string
Type string
)
// get redis key
func GetRedisKey(redisurl string, redistoken string) string {
client := &http.Client{}
req, err := http.NewRequest("GET", redisurl, nil)
req.SetBasicAuth("redis", redistoken)
resp, err := client.Do(req)
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
log.Fatalf("[ERROR] Fail to read %v: %v", redisurl, err)
}
return fmt.Sprintf(string(body))
}
// create directory structure and write certificate to file
func WriteToFile(content string, destination string, groupname string, filemode os.FileMode, dirmode os.FileMode) {
baseDir := filepath.Dir(destination)
if _, err := os.Stat(baseDir); os.IsNotExist(err) {
os.MkdirAll(baseDir, 0755)
}
os.Chmod(baseDir, dirmode)
file, err := os.OpenFile(destination, os.O_WRONLY|os.O_CREATE, filemode)
if err != nil {
log.Fatalf("[ERROR] %v cannot be created", destination)
}
fmt.Fprintf(file, "%v\n", content)
file.Close()
}
// ReadOSRelease from /etc/os-release
func ReadOSRelease(configfile string) map[string]string {
cfg, err := ini.Load(configfile)
if err != nil {
log.Fatal("[ERROR] Fail to read file: ", err)
}
ConfigParams := make(map[string]string)
ConfigParams["ID"] = cfg.Section("").Key("ID").String()
return ConfigParams
}
func main() {
OSInfo := ReadOSRelease("/etc/os-release")
OSRelease := OSInfo["ID"]
if OSRelease == "centos" || OSRelease == "rhel" {
CertBase = "/etc/pki/tls/certs"
KeyBase = "/etc/pki/tls/private"
GroupName = "root"
} else if OSRelease == "ubuntu" || OSRelease == "debian" {
CertBase = "/etc/ssl/certs"
KeyBase = "/etc/ssl/private"
GroupName = "ssl-cert"
}
usage := fmt.Sprintf(`ACME Downloader:
- fetches and stores a given Certificate, Full Chain, CA and Private Key
Usage:
acme-downloader --redis-token=REDISTOKEN --vault-token=VAULTTOKEN --cert-name=CERTNAME --team-name=TEAMNAME [--days=DAYS] [--type=TYPE] [--cert-destination=CERTDESTINATION] [--fullchain-destination=FULLCHAINDESTINATION] [--key-destination=KEYDESTINATION] [--ca-destination=CADESTINATION]
acme-downloader -v | --version
acme-downloader -b | --build
acme-downloader -h | --help
Options:
-h --help Show this screen
-v --version Print version exit
-b --build Print version and build information and exit
--redis-token=REDISTOKEN Redis access token
--vault-token=VAULTTOKEN Vault access token
--cert-name=CERTNAME Certificate name
--team-name=TEAMNAME Team name: swd, dream_team, it, ne, ti...
--days=DAYS Days before expiration [default: 30]
--type=TYPE Type, EV or OV [default: EV]
--cert-destination=CERTDESTINATION Cert Destination [default: %v/<cert-name>.crt]
--fullchain-destination=FULLCHAINDESTINATION Full Chain Destination[default: %v/<cert-name>_fullchain.crt]
--key-destination=KEYDESTINATION Key Destination [default: %v/<cert-name>.key]
--ca-destination=CADESTINATION CA Destination [default: %v/COMODO_<type>.crt]
`, CertBase, CertBase, KeyBase, CertBase)
// Annoyingly docopt tries to use 'version' the way he wants and I am using build
arguments, _ := docopt.Parse(usage, nil, true, appVersion, false)
if arguments["--build"] == true {
fmt.Printf("acme-downloader version: %v, built on: %v\n", appVersion, buildTime)
os.Exit(0)
}
VaultToken := arguments["--vault-token"].(string)
CertName := arguments["--cert-name"].(string)
CertNameUndercored := strings.Replace(CertName, ".", "_", -1)
TeamName := arguments["--team-name"].(string)
RedisToken := arguments["--redis-token"].(string)
Type = arguments["--type"].(string)
RedisBaseURL = "https://redis.geant.org/GET"
VaultBaseURL = "https://vault.geant.org/v1"
VaultURL := fmt.Sprintf("%v/%v/%v/vault_%v_key", VaultBaseURL, TeamName, CertName, CertNameUndercored)
RedisCertURL := fmt.Sprintf("%v/%v:%v:redis_%v_pem.txt", RedisBaseURL, TeamName, CertName, CertNameUndercored)
RedisCAURL := fmt.Sprintf("%v/%v:%v:redis_%v_chain_pem.txt", RedisBaseURL, TeamName, CertName, CertNameUndercored)
RedisFullChainURL := fmt.Sprintf("%v/%v:%v:redis_%v_fullchain_pem.txt", RedisBaseURL, TeamName, CertName, CertNameUndercored)
certificate := GetRedisKey(RedisCertURL, RedisToken)
ca := GetRedisKey(RedisCAURL, RedisToken)
fullChain := GetRedisKey(RedisFullChainURL, RedisToken)
if arguments["--cert-destination"] == fmt.Sprintf("%v/<cert-name>.crt", CertBase) {
certificateDestination = fmt.Sprintf("%v/%v.crt", CertBase, CertName)
} else {
certificateDestination = arguments["--cert-destination"].(string)
}
if arguments["--fullchain-destination"] == fmt.Sprintf("%v/<cert-name>_fullchain.crt", CertBase) {
fullchainDestination = fmt.Sprintf("%v/%v_fullchain.crt", CertBase, CertName)
} else {
fullchainDestination = arguments["--fullchain-destination"].(string)
}
if arguments["--key-destination"] == fmt.Sprintf("%v/<cert-name>.key", KeyBase) {
keyDestination = fmt.Sprintf("%v/%v.key", KeyBase, CertName)
} else {
keyDestination = arguments["--key-destination"].(string)
}
if arguments["--ca-destination"] == fmt.Sprintf("%v/COMODO_<type>.crt", CertBase) {
caDestination = fmt.Sprintf("%v/COMODO_%v.crt", CertBase, Type)
} else {
caDestination = arguments["--ca-destination"].(string)
}
// get Vault key
vaultClient := &http.Client{}
vaultReq, err := http.NewRequest("GET", VaultURL, nil)
vaultReq.Header.Add("X-vault-token", VaultToken)
vaultResp, err := vaultClient.Do(vaultReq)
vaultBody, err := ioutil.ReadAll(vaultResp.Body)
defer vaultResp.Body.Close()
if err != nil {
log.Fatalf("Fail to read %v: %v", VaultURL, err)
}
privKey := gjson.Get(string(vaultBody), "data.value").String()
WriteToFile(certificate, certificateDestination, GroupName, 0644, 0755)
WriteToFile(fullChain, fullchainDestination, GroupName, 0644, 0755)
WriteToFile(ca, caDestination, GroupName, 0644, 0755)
WriteToFile(privKey, keyDestination, GroupName, 0640, 0750)
fmt.Printf("installed: %v\n", certificateDestination)
fmt.Printf("installed: %v\n", caDestination)
fmt.Printf("installed: %v\n", fullchainDestination)
fmt.Printf("installed: %v\n", keyDestination)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment