package main import ( "github.com/hashicorp/consul/api" "errors" "log" "fmt" "os" "encoding/base64" /*"github.com/aws/aws-sdk-go/service/s3"*/ ) const consul_addr string = "KV2S3_CONSUL_ADDR" const enc_key string = "KV2S3_ENC_KEY" const key_exp_bits int = 256 const key_exp_bytes int = key_exp_bits / 8 func errIsPanic(err error, format string, a ...interface{}) { if err != nil { log.Panicf(format, a...) } } func absentIsErr(present bool) error { if !present { return errors.New("Environement variable is not set.") } return nil } func main() { log.Println("starting consul kv backup...") //--- Ask Consul to Snapshot our KV var present bool conf := api.DefaultConfig() conf.Address, present = os.LookupEnv(consul_addr) err := absentIsErr(present) errIsPanic(err, "%v env required. %v", consul_addr, err) //@FIXME add later support for HTTPS options := api.QueryOptions { // Prevent from backuping forever silently a desynchronized node AllowStale: false, } consul, err := api.NewClient(conf) errIsPanic(err, "Unable to build a new client. %v", err) reader, _, err := consul.Snapshot().Save(&options) errIsPanic(err, "Snapshot failed. %v", err) //--- Get encryption key and check it b64_key, present := os.LookupEnv(enc_key) err = absentIsErr(present) errIsPanic(err, "%v env required. %v", enc_key, err) raw_key, err := base64.StdEncoding.DecodeString(b64_key) errIsPanic(err, "Unable to decode base64 key. %v", err) err = nil key_size_bytes := len(raw_key) key_size_bits := key_size_bytes if key_size_bytes != key_exp_bytes { msg := fmt.Sprintf( "Key size is %d bits (%d bytes) instead of %d bits (%d bytes).", key_size_bits, key_size_bytes, key_exp_bits, key_exp_bytes) err = errors.New(msg) } errIsPanic(err, "We deliberately support only 256 bits (32 bytes) keys. %v", err) //--- Encryption // Not a simple thing to do it in a streaming manner // To understand why age by Filippo Valsorda seems to be a good fit: // https://neilmadden.blog/2019/12/30/a-few-comments-on-age/ }