Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vault_token: add pgp_key support #686

Merged
merged 5 commits into from
Mar 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f h1:Gsc9mVHLRqBjMgdQCghN9NObCcRncDqxJvBvEaIIQEo=
github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
Expand Down
42 changes: 41 additions & 1 deletion vault/resource_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/encryption"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/vault/api"
)
Expand Down Expand Up @@ -143,6 +144,18 @@ func tokenResource() *schema.Resource {
Description: "The client wrapping accessor.",
Sensitive: true,
},
"pgp_key": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Description: "The PGP key (base64 encoded) to encrypt the token.",
},
"encrypted_client_token": {
Type: schema.TypeString,
Computed: true,
Description: "The client token encrypted using the provided PGP key.",
Sensitive: true,
},
},
}
}
Expand Down Expand Up @@ -253,7 +266,23 @@ func tokenCreate(d *schema.ResourceData, meta interface{}) error {
d.Set("wrapped_token", resp.WrapInfo.Token)
d.Set("wrapping_accessor", resp.WrapInfo.Accessor)
} else {
d.Set("client_token", resp.Auth.ClientToken)
if v, ok := d.GetOk("pgp_key"); ok {
pgpKey := v.(string)
encryptionKey, err := encryption.RetrieveGPGKey(pgpKey)
if err != nil {
return err
}
_, encrypted, err := encryption.EncryptValue(encryptionKey, resp.Auth.ClientToken, "Vault Token")
if err != nil {
return err
}
d.Set("client_token", "")
d.Set("encrypted_client_token", encrypted)
} else {
d.Set("pgp_key", "")
d.Set("client_token", resp.Auth.ClientToken)
d.Set("encrypted_client_token", "")
}
}

d.SetId(accessor)
Expand Down Expand Up @@ -292,6 +321,12 @@ func tokenRead(d *schema.ResourceData, meta interface{}) error {
d.Set("renewable", resp.Data["renewable"])
d.Set("display_name", strings.TrimPrefix(resp.Data["display_name"].(string), "token-"))
d.Set("num_uses", resp.Data["num_uses"])
if _, ok := d.GetOk("pgp_key"); !ok {
d.Set("pgp_key", "")
}
if _, ok := d.GetOk("encrypted_client_token"); !ok {
d.Set("encrypted_client_token", "")
}

issueTime, err := time.Parse(time.RFC3339Nano, resp.Data["issue_time"].(string))
if err != nil {
Expand All @@ -306,6 +341,11 @@ func tokenRead(d *schema.ResourceData, meta interface{}) error {
d.Set("lease_duration", int(expireTime.Sub(issueTime).Seconds()))

if d.Get("renewable").(bool) && tokenCheckLease(d) {
if id == "" {
log.Printf("[DEBUG] Lease for token access %q cannot be renewed as it's been encrypted.", accessor)
return nil
}

log.Printf("[DEBUG] Lease for token accessor %q expiring soon, renewing", accessor)

increment := d.Get("lease_duration").(int)
Expand Down
46 changes: 45 additions & 1 deletion vault/resource_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func TestResourceToken_basic(t *testing.T) {
resource.TestCheckResourceAttrSet("vault_token.test", "lease_duration"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttrSet("vault_token.test", "client_token"),
resource.TestCheckResourceAttr("vault_token.test", "encrypted_client_token", ""),
),
},
},
Expand All @@ -59,14 +60,15 @@ func TestResourceToken_import(t *testing.T) {
resource.TestCheckResourceAttrSet("vault_token.test", "lease_duration"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttrSet("vault_token.test", "client_token"),
resource.TestCheckResourceAttr("vault_token.test", "encrypted_client_token", ""),
),
},
{
ResourceName: "vault_token.test",
ImportState: true,
ImportStateVerify: true,
// the API can't serve these fields, so ignore them
ImportStateVerifyIgnore: []string{"ttl", "lease_duration", "lease_started", "client_token"},
ImportStateVerifyIgnore: []string{"ttl", "lease_duration", "lease_started", "client_token", "encrypted_client_token"},
},
},
})
Expand Down Expand Up @@ -108,6 +110,7 @@ func TestResourceToken_full(t *testing.T) {
resource.TestCheckResourceAttr("vault_token.test", "lease_duration", "59"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttrSet("vault_token.test", "client_token"),
resource.TestCheckResourceAttr("vault_token.test", "encrypted_client_token", ""),
),
},
},
Expand Down Expand Up @@ -206,6 +209,7 @@ func TestResourceToken_expire(t *testing.T) {
resource.TestCheckResourceAttr("vault_token.test", "lease_duration", "9"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttrSet("vault_token.test", "client_token"),
resource.TestCheckResourceAttr("vault_token.test", "encrypted_client_token", ""),
),
},
},
Expand Down Expand Up @@ -243,6 +247,7 @@ func TestResourceToken_renew(t *testing.T) {
resource.TestCheckResourceAttr("vault_token.test", "lease_duration", "29"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttrSet("vault_token.test", "client_token"),
resource.TestCheckResourceAttr("vault_token.test", "encrypted_client_token", ""),
),
},
{
Expand All @@ -256,6 +261,7 @@ func TestResourceToken_renew(t *testing.T) {
resource.TestCheckResourceAttrSet("vault_token.test", "lease_duration"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttrSet("vault_token.test", "client_token"),
resource.TestCheckResourceAttr("vault_token.test", "encrypted_client_token", ""),
),
},
{
Expand All @@ -272,6 +278,7 @@ func TestResourceToken_renew(t *testing.T) {
resource.TestCheckResourceAttr("vault_token.test", "lease_duration", "29"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttrSet("vault_token.test", "client_token"),
resource.TestCheckResourceAttr("vault_token.test", "encrypted_client_token", ""),
),
},
},
Expand Down Expand Up @@ -424,3 +431,40 @@ func testResourceTokenWaitRenewMinLeaseTime(n string) resource.TestCheckFunc {
return nil
}
}

func TestResourceToken_pgp(t *testing.T) {
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testResourceTokenCheckDestroy,
Steps: []resource.TestStep{
{
Config: testResourceTokenConfig_pgp(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_token.test", "policies.#", "1"),
resource.TestCheckResourceAttr("vault_token.test", "ttl", "60s"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_duration"),
resource.TestCheckResourceAttrSet("vault_token.test", "lease_started"),
resource.TestCheckResourceAttr("vault_token.test", "client_token", ""),
resource.TestCheckResourceAttrSet("vault_token.test", "encrypted_client_token"),
),
},
},
})
}

func testResourceTokenConfig_pgp() string {
return `
resource "vault_policy" "test" {
name = "test"
policy = <<EOT
path "secret/*" { capabilities = [ "list" ] }
EOT
}

resource "vault_token" "test" {
ttl = "60s"
policies = [ "${vault_policy.test.name}" ]
pgp_key = "keybase:terraformacctest"
}`
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading