Skip to content

Instantly share code, notes, and snippets.

@stefansundin
Last active May 1, 2020 18:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefansundin/428c1f3dfcbddf58202477c48d4c8fef to your computer and use it in GitHub Desktop.
Save stefansundin/428c1f3dfcbddf58202477c48d4c8fef to your computer and use it in GitHub Desktop.
Vault transit encryption and datakey testing, with uploads to S3 and GCloud. Ruby and Go. Also see https://gist.github.com/stefansundin/426a5b14bfbbb722d09b383c9724c6b1.

Vault:

Ruby:

Go:

Implementation details

The transit option doesn't require the client to perform any crypto operations on its own, but it does not scale if the data sizes grow large.

For large blobs, envelope encryption is a must to avoid bringing down the key store (vault). This example uses AES/GCM with strict authentication mode.

Go appends the auth tag to the end of the ciphertext automatically. Ruby doesn't do this automatically, so the Ruby code has been adjusted to emulate Go.

The nonce is randomly generated and the same one should never be reused for the same data key, but since each object gets its own data key from Vault, there should be no risk of this happening.

Setup Vault

docker-compose up -d
export VAULT_ADDR=http://localhost:8200
vault operator init -n 1 -t 1
vault operator unseal <unseal_key>
vault login <root_token>
vault secrets enable transit

Create the transit key (optionally pick a cipher other than the default):

vault write -f transit/keys/mykeyname

How to run

Ruby:

./encrypt-transit.rb
./decrypt-transit.rb

./encrypt-datakey.rb
./decrypt-datakey.rb

Go:

go run shared.go encrypt-transit.go
go run shared.go decrypt-transit.go

go run shared.go encrypt-datakey.go
go run shared.go decrypt-datakey.go

Cloud compatibility

Google Cloud has an implementation of the S3 API. The "Interoperability API" has to be enabled. Enable it, create a storage bucket, and generate an access key.

Azure does not seem to support the S3 API. I found several examples where people use proxies and are able to use the AWS SDK that way. I did not try this.

Set up two profiles in ~/.aws/credentials, one for AWS and one for GCloud:

[s3test_aws]
region=us-west-2
aws_access_key_id=ABC
aws_secret_access_key=XYZ

[s3test_gcloud]
region=does-not-matter
aws_access_key_id=GOOG1EABC
aws_secret_access_key=XYZ
package main
import (
"encoding/base64"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/aws/aws-sdk-go/aws"
// "github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func main() {
s3Bucket := "s3test-bucket"
s3Key := "secret-datakey.txt"
vaultRoute := "transit/decrypt/mykeyname"
// To use AWS:
s3Session := session.Must(session.NewSessionWithOptions(session.Options{
Profile: "s3test_aws",
SharedConfigState: session.SharedConfigEnable,
}))
// To use GCloud:
// customResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
// if service == endpoints.S3ServiceID {
// return endpoints.ResolvedEndpoint{
// URL: "https://storage.googleapis.com",
// }, nil
// }
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
// }
// s3Session := session.Must(session.NewSessionWithOptions(session.Options{
// Profile: "s3test_gcloud",
// SharedConfigState: session.SharedConfigEnable,
// Config: aws.Config{
// EndpointResolver: endpoints.ResolverFunc(customResolver),
// },
// }))
s3Client := s3.New(s3Session)
respGet, err := s3Client.GetObject(&s3.GetObjectInput{
Bucket: aws.String(s3Bucket),
Key: aws.String(s3Key),
})
check(err)
ciphertext, err := ioutil.ReadAll(respGet.Body)
check(err)
fmt.Printf("Ciphertext: %v\n", ciphertext)
fmt.Printf("Metadata: %v\n", respGet.Metadata)
nonceBase64, ok1 := respGet.Metadata["Gcm-Nonce"]
datakeyCiphertext, ok2 := respGet.Metadata["Vault-Datakey"]
if !ok1 || !ok2 {
fmt.Println("The object is missing the required metadata.")
os.Exit(1)
}
fmt.Printf("GCM nonce: %s\n", *nonceBase64)
fmt.Printf("Datakey ciphertext: %s\n", *datakeyCiphertext)
if !strings.HasPrefix(*datakeyCiphertext, "vault:") {
fmt.Println("This datakey does not have the correct prefix.")
os.Exit(1)
}
vaultClient := NewVaultClient()
secret, err := vaultClient.Logical().Write(vaultRoute, map[string]interface{}{
"ciphertext": *datakeyCiphertext,
})
check(err)
datakeyPlaintext := secret.Data["plaintext"].(string)
fmt.Printf("Datakey plaintext: %s\n", datakeyPlaintext)
datakeyBytes, err := base64.StdEncoding.DecodeString(datakeyPlaintext)
check(err)
nonceRaw, err := base64.StdEncoding.DecodeString(*nonceBase64)
plaintext := DecryptData_AESGCM(ciphertext, datakeyBytes, nonceRaw)
fmt.Printf("Plaintext: %s\n", plaintext)
}
#!/usr/bin/env ruby
require 'openssl'
require 'base64'
require 'vault'
require 'aws-sdk-s3'
s3_bucket = 's3test-bucket'
s3_key = 'secret-datakey.txt'
vault_route = 'transit/decrypt/mykeyname'
auth_tag_size = 16
s3_client = Aws::S3::Client.new(
# To use AWS:
profile: 's3test_aws',
# To use GCloud:
# profile: 's3test_gcloud',
# endpoint: 'https://storage.googleapis.com',
# region: 'does-not-matter',
)
resp = s3_client.get_object(
bucket: s3_bucket,
key: s3_key,
)
blob = resp.body.read
ciphertext = blob[...-auth_tag_size]
auth_tag = blob[-auth_tag_size..]
puts "Ciphertext: #{ciphertext.bytes.to_a}"
puts "Metadata: #{resp.metadata}"
datakey_ciphertext = resp.metadata["vault-datakey"]
nonce_base64 = resp.metadata["gcm-nonce"]
# auth_tag_base64 = resp.metadata["gcm-auth-tag"]
if !datakey_ciphertext || !nonce_base64 #|| !auth_tag_base64
abort "The object is missing the required metadata."
end
puts "GCM nonce: #{nonce_base64}"
puts "Datakey ciphertext: #{datakey_ciphertext}"
if !datakey_ciphertext.start_with?("vault:")
abort "This datakey does not have the correct prefix."
end
vault_client = Vault::Client.new(ssl_verify: false)
secret = vault_client.logical.write(vault_route, {
ciphertext: datakey_ciphertext,
})
datakey_plaintext = secret.data[:plaintext]
puts "Datakey plaintext: #{datakey_plaintext}"
aes = OpenSSL::Cipher::AES.new(256, :GCM).decrypt
aes.key = Base64.strict_decode64(datakey_plaintext)
aes.iv = Base64.decode64(nonce_base64)
aes.auth_tag = auth_tag
aes.auth_data = ""
plaintext = aes.update(ciphertext) + aes.final
puts "Plaintext: #{plaintext}"
package main
import (
"bytes"
"encoding/base64"
"fmt"
"os"
"strings"
"github.com/aws/aws-sdk-go/aws"
// "github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func main() {
s3Bucket := "s3test-bucket"
s3Key := "secret-transit.txt"
vaultRoute := "transit/decrypt/mykeyname"
// To use AWS:
s3Session := session.Must(session.NewSessionWithOptions(session.Options{
Profile: "s3test_aws",
SharedConfigState: session.SharedConfigEnable,
}))
// To use GCloud:
// customResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
// if service == endpoints.S3ServiceID {
// return endpoints.ResolvedEndpoint{
// URL: "https://storage.googleapis.com",
// }, nil
// }
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
// }
// s3Session := session.Must(session.NewSessionWithOptions(session.Options{
// Profile: "s3test_gcloud",
// SharedConfigState: session.SharedConfigEnable,
// Config: aws.Config{
// EndpointResolver: endpoints.ResolverFunc(customResolver),
// },
// }))
s3Client := s3.New(s3Session)
respGet, err := s3Client.GetObject(&s3.GetObjectInput{
Bucket: aws.String(s3Bucket),
Key: aws.String(s3Key),
})
check(err)
buf := new(bytes.Buffer)
buf.ReadFrom(respGet.Body)
ciphertext := buf.String()
fmt.Printf("Ciphertext: %s\n", ciphertext)
if !strings.HasPrefix(ciphertext, "vault:") {
fmt.Println("It does not look like this data was encrypted with Vault.")
os.Exit(1)
}
vaultClient := NewVaultClient()
secret, err := vaultClient.Logical().Write(vaultRoute, map[string]interface{}{
"ciphertext": ciphertext,
})
check(err)
data, err := base64.StdEncoding.DecodeString(secret.Data["plaintext"].(string))
check(err)
plaintext := string(data)
fmt.Printf("Plaintext: %s\n", plaintext)
}
#!/usr/bin/env ruby
require 'vault'
require 'aws-sdk-s3'
s3_bucket = 's3test-bucket'
s3_key = 'secret-transit.txt'
vault_route = 'transit/decrypt/mykeyname'
s3_client = Aws::S3::Client.new(
# To use AWS:
profile: 's3test_aws',
# To use GCloud:
# profile: 's3test_gcloud',
# endpoint: 'https://storage.googleapis.com',
# region: 'does-not-matter',
)
resp = s3_client.get_object(
bucket: s3_bucket,
key: s3_key,
)
ciphertext = resp.body.read
puts "Ciphertext: #{ciphertext}"
if !ciphertext.start_with?("vault:")
abort "It does not look like this data was encrypted with Vault."
end
vault_client = Vault::Client.new(ssl_verify: false)
secret = vault_client.logical.write(vault_route, {
ciphertext: ciphertext,
})
plaintext = Base64.strict_decode64(secret.data[:plaintext])
puts "Plaintext: #{plaintext}"
version: "3"
services:
vault:
image: vault
command: ["server"]
environment:
VAULT_API_ADDR: http://localhost:8200
VAULT_LOCAL_CONFIG: |
{
"backend": {"file": {"path": "/vault/file"}},
"listener": {"tcp": {"address": "0.0.0.0:8200", "tls_disable": true}},
"ui": true,
"default_lease_ttl": "168h",
"max_lease_ttl": "720h"
}
ports:
- 8200:8200
cap_add:
- IPC_LOCK
package main
import (
"bytes"
"encoding/base64"
"fmt"
"time"
"github.com/aws/aws-sdk-go/aws"
// "github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func main() {
s3Bucket := "s3test-bucket"
s3Key := "secret-datakey.txt"
plaintext := "this is a very secret string"
vaultRoute := "transit/datakey/plaintext/mykeyname"
fmt.Printf("Plaintext: %s\n", plaintext)
vaultClient := NewVaultClient()
datakey, err := vaultClient.Logical().Write(vaultRoute, nil)
check(err)
datakeyPlaintext := datakey.Data["plaintext"].(string)
datakeyCiphertext := datakey.Data["ciphertext"].(string)
fmt.Printf("Datakey plaintext: %s\n", datakeyPlaintext)
fmt.Printf("Datakey ciphertext: %s\n", datakeyCiphertext)
datakeyBytes, err := base64.StdEncoding.DecodeString(datakeyPlaintext)
check(err)
ciphertext, nonceRaw := EncryptData_AESGCM([]byte(plaintext), datakeyBytes)
nonceBase64 := base64.StdEncoding.EncodeToString(nonceRaw)
fmt.Printf("GCM nonce: %s\n", nonceBase64)
fmt.Printf("Ciphertext: %v\n", ciphertext)
// To use AWS:
s3Session := session.Must(session.NewSessionWithOptions(session.Options{
Profile: "s3test_aws",
SharedConfigState: session.SharedConfigEnable,
}))
// To use GCloud:
// customResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
// if service == endpoints.S3ServiceID {
// return endpoints.ResolvedEndpoint{
// URL: "https://storage.googleapis.com",
// }, nil
// }
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
// }
// s3Session := session.Must(session.NewSessionWithOptions(session.Options{
// Profile: "s3test_gcloud",
// SharedConfigState: session.SharedConfigEnable,
// Config: aws.Config{
// EndpointResolver: endpoints.ResolverFunc(customResolver),
// },
// }))
s3Client := s3.New(s3Session)
respPut, err := s3Client.PutObject(&s3.PutObjectInput{
Bucket: aws.String(s3Bucket),
Key: aws.String(s3Key),
Body: bytes.NewReader([]byte(ciphertext)),
Metadata: map[string]*string{
"Vault-Datakey": aws.String(datakeyCiphertext),
"Gcm-Nonce": aws.String(nonceBase64),
},
})
check(err)
fmt.Println(respPut)
time.Sleep(1 * time.Second)
respHead, err := s3Client.HeadObject(&s3.HeadObjectInput{
Bucket: aws.String(s3Bucket),
Key: aws.String(s3Key),
})
fmt.Println()
fmt.Println("Object metadata:")
for k, v := range respHead.Metadata {
fmt.Printf("%v: %v\n", k, *v)
}
}
#!/usr/bin/env ruby
require 'openssl'
require 'base64'
require 'vault'
require 'aws-sdk-s3'
s3_bucket = 's3test-bucket'
s3_key = 'secret-datakey.txt'
plaintext = 'this is a very secret string'
vault_route = 'transit/datakey/plaintext/mykeyname'
puts "Plaintext: #{plaintext}"
vault_client = Vault::Client.new(ssl_verify: false)
datakey = vault_client.logical.write(vault_route)
datakey_plaintext = datakey.data[:plaintext]
datakey_ciphertext = datakey.data[:ciphertext]
puts "Datakey plaintext: #{datakey_plaintext}"
puts "Datakey ciphertext: #{datakey_ciphertext}"
datakey_bytes = Base64.strict_decode64(datakey_plaintext)
aes = OpenSSL::Cipher::AES.new(256, :GCM).encrypt
aes.key = datakey_bytes
nonce_raw = aes.random_iv
nonce_base64 = Base64.strict_encode64(nonce_raw)
ciphertext = aes.update(plaintext) + aes.final
ciphertext += aes.auth_tag
puts "GCM nonce: #{nonce_base64}"
puts "Ciphertext: #{ciphertext.bytes.to_a}"
s3_client = Aws::S3::Client.new(
# To use AWS:
profile: 's3test_aws',
# To use GCloud:
# profile: 's3test_gcloud',
# endpoint: 'https://storage.googleapis.com',
# region: 'does-not-matter',
)
resp = s3_client.put_object(
bucket: s3_bucket,
key: s3_key,
body: ciphertext,
metadata: {
"gcm-nonce" => nonce_base64,
"vault-datakey" => datakey_ciphertext,
},
)
puts resp.inspect
sleep(1)
puts
puts "Object metadata:"
resp = s3_client.head_object(bucket: s3_bucket, key: s3_key)
puts resp.metadata.inspect
package main
import (
"bytes"
"encoding/base64"
"fmt"
"github.com/aws/aws-sdk-go/aws"
// "github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func main() {
s3Bucket := "s3test-bucket"
s3Key := "secret-transit.txt"
plaintext := "this is a very secret string"
vaultRoute := "transit/encrypt/mykeyname"
fmt.Printf("Plaintext: %s\n", plaintext)
vaultClient := NewVaultClient()
secret, err := vaultClient.Logical().Write(vaultRoute, map[string]interface{}{
"plaintext": base64.StdEncoding.EncodeToString([]byte(plaintext)),
})
check(err)
data := secret.Data["ciphertext"].(string)
ciphertext := string(data)
fmt.Printf("Ciphertext: %s\n", ciphertext)
// To use AWS:
s3Session := session.Must(session.NewSessionWithOptions(session.Options{
Profile: "s3test_aws",
SharedConfigState: session.SharedConfigEnable,
}))
// To use GCloud:
// customResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
// if service == endpoints.S3ServiceID {
// return endpoints.ResolvedEndpoint{
// URL: "https://storage.googleapis.com",
// }, nil
// }
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
// }
// s3Session := session.Must(session.NewSessionWithOptions(session.Options{
// Profile: "s3test_gcloud",
// SharedConfigState: session.SharedConfigEnable,
// Config: aws.Config{
// EndpointResolver: endpoints.ResolverFunc(customResolver),
// },
// }))
s3Client := s3.New(s3Session)
respPut, err := s3Client.PutObject(&s3.PutObjectInput{
Bucket: aws.String(s3Bucket),
Key: aws.String(s3Key),
Body: bytes.NewReader([]byte(ciphertext)),
})
check(err)
fmt.Println(respPut)
}
#!/usr/bin/env ruby
require 'vault'
require 'aws-sdk-s3'
s3_bucket = 's3test-bucket'
s3_key = 'secret-transit.txt'
plaintext = 'this is a very secret string'
vault_route = 'transit/encrypt/mykeyname'
puts "Plaintext: #{plaintext}"
vault_client = Vault::Client.new(ssl_verify: false)
secret = vault_client.logical.write(vault_route, {
plaintext: Base64.strict_encode64(plaintext),
})
ciphertext = secret.data[:ciphertext]
puts "Ciphertext: #{ciphertext}"
s3_client = Aws::S3::Client.new(
# To use AWS:
profile: 's3test_aws',
# To use GCloud:
# profile: 's3test_gcloud',
# endpoint: 'https://storage.googleapis.com',
# region: 'does-not-matter',
)
resp = s3_client.put_object(
bucket: s3_bucket,
key: s3_key,
body: ciphertext,
)
puts resp.inspect
source "https://rubygems.org"
gem "vault"
gem "aws-sdk-s3"
GEM
remote: https://rubygems.org/
specs:
aws-eventstream (1.0.3)
aws-partitions (1.295.0)
aws-sdk-core (3.93.0)
aws-eventstream (~> 1.0, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.30.0)
aws-sdk-core (~> 3, >= 3.71.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.61.2)
aws-sdk-core (~> 3, >= 3.83.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.1)
aws-eventstream (~> 1.0, >= 1.0.2)
jmespath (1.4.0)
vault (0.13.1)
aws-sigv4 (= 1.1.1)
PLATFORMS
ruby
DEPENDENCIES
aws-sdk-s3
vault
BUNDLED WITH
2.1.4
module s3test
go 1.14
require (
github.com/aws/aws-sdk-go v1.30.6
github.com/hashicorp/vault/api v1.0.4
github.com/mitchellh/go-homedir v1.1.0
)
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.30.6 h1:GuWgFWWR9CF8mO9SM6N9oZt0vM0yzgPCMDDZOEQb8l4=
github.com/aws/aws-sdk-go v1.30.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/vault v1.4.0 h1:pe4kdAs0Wogqv/3yi91FInkN5PXuY4IMnjgz3LurGtg=
github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU=
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8=
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"os"
"path/filepath"
"strings"
vault "github.com/hashicorp/vault/api"
homedir "github.com/mitchellh/go-homedir"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func NewVaultClient() *vault.Client {
client, err := vault.NewClient(nil)
check(err)
if client.Token() == "" {
client.SetToken(GetVaultTokenFromFile())
}
return client
}
// this is not supported in the SDK itself, but is in the Ruby SDK
// for convenience, replicating it here from https://github.com/hashicorp/vault/blob/124572bf80150689e747dbe84db0b76f4a1a6ad0/command/token/helper_internal.go
func GetVaultTokenFromFile() string {
homeDir, err := homedir.Dir()
check(err)
f, err := os.Open(filepath.Join(homeDir, ".vault-token"))
check(err)
defer f.Close()
buf := bytes.NewBuffer(nil)
_, err = io.Copy(buf, f)
check(err)
return strings.TrimSpace(buf.String())
}
func EncryptData_AESGCM(data []byte, key []byte) ([]byte, []byte) {
block, err := aes.NewCipher(key)
check(err)
nonce := make([]byte, 12)
_, err = io.ReadFull(rand.Reader, nonce)
check(err)
aesgcm, err := cipher.NewGCM(block)
check(err)
ciphertext := aesgcm.Seal(nil, nonce, data, nil)
return ciphertext, nonce
}
func DecryptData_AESGCM(ciphertext []byte, key []byte, nonce []byte) []byte {
block, err := aes.NewCipher(key)
check(err)
aesgcm, err := cipher.NewGCM(block)
check(err)
data, err := aesgcm.Open(nil, nonce, ciphertext, nil)
check(err)
return data
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment