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

Initial commit

parents
No related branches found
No related tags found
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.
Finish editing this message first!
Please register or to comment