Categories
Uncategorized

Extracting secrets from AWS-Vault

Recently I was in the situation in which I needed to do some automation involving AWS-Vault, which is a tool for securely managing AWS access keys on developer workstations. Until now I had been using the file backend, which relies on encrypted-at-rest files to store the secrets.

Since there is obviously no caching involved here, every time I wanted to use a secret I would need to type in the passphrase to unlock it, with no cached copy of the passphrase involved. Coupled with a bug that my team faces when applying Terraform (sessions cause remote state S3 bucket reads to fail, worked around with the --no-session option), there was no way that I could create a loop for it.

The solution for this was to move to a different backend. Since I run Linux on my workstation, that meant moving to the secret-service backend, which in my case is backed by gnome-keyring-daemon.

Researching this yielded no solution for how to migrate from one backend to another. There was nothing in a contrib/ directory or any blog posts, so instead I had a dig into the source code. This showed that the AWS-Vault key files (located in $HOME/.awsvault/keys were a base64-encoded blob, that when decoded revealed some JSON content from a standard called JOSE (Javascript Object Signing and Encryption). Specifically, I learned that they contained JWK (Javascript Web Key) attributes, although just trying to decoded it yielded encoding errors:

$ cat .awsvault/keys/mykey |base64 -d
{"alg":"PBES2-HS256+A128KW","created":"2019-12-04 09:33:34.461409668 -0800 PST m=+9.768812157","enc":"A256GCM","p2c":8192,"p2s":"FFFFFFFFFFF"}base64: invalid input

“Perfect, from here on out I can just find a good JOSE library in my language of choice, load it up, and print the payload” was what I thought. This didn’t end up working though. I wasn’t able to figure out a workable method using python-jose, try as I might. My next effort was simply replicate the libraries and methods from the original file in AWS-Vault’s keyring library. This actually ended up working. The final code for this is as follows:

package main

import (
    jose "github.com/dvsekhvalnov/jose2go"
    "fmt"
    "io/ioutil"
    "os"
    "encoding/json"
)

type Item struct {
    Key         string
    Data        []byte
    Label       string
    Description string

    // Backend specific config
    KeychainNotTrustApplication bool
    KeychainNotSynchronizable   bool
}

type Key struct {
    AccessKeyID         string
    SecretAccessKey     string
    SessionToken        string
}

func main() {
    if len(os.Args) != 3 {
       fmt.Println("Wrong input format, expected: ./aws-vault-decrypt <key_file> <password>")
       os.Exit(1)
    }

    bytes, err := ioutil.ReadFile(os.Args[1])
    if os.IsNotExist(err) {
        fmt.Println("File not found")
    }
    if err != nil {
        fmt.Printf("Error: %s", err)
    }

    payload, _, err := jose.Decode(string(bytes), os.Args[2])
    //fmt.Printf(payload)
    var decoded = Item{}
    err = json.Unmarshal([]byte(payload), &decoded)
    var data = Key{}
    err = json.Unmarshal([]byte(decoded.Data), &data)
    fmt.Printf("AWS_ACCESS_KEY_ID: %s\n", string(data.AccessKeyID))
    fmt.Printf("AWS_SECRET_ACCESS_KEY: %s\n", string(data.SecretAccessKey))
}

This resulted in good output:

$ ./aws-vault-decrypt /home/bkero/.awsvault/keys/mykey 'mypassword'
AWS_ACCESS_KEY_ID: AKIAXXXXXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY: XXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

From here it was simply a matter of setting my new backend in AWS-Vault and running aws-vault add:

$ export AWS_VAULT_BACKEND=secret-service
$ aws-vault add mykey
Enter Access Key ID: AKIAXXXXXXXXXXXXXXXX
Enter Secret Access Key: XXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Added credentials to profile "mykey" in vault

Note that you’ll want to add that export AWS_VAULT_BACKEND=secret-service line to your $HOME/.bashrc if you want the change to be permanent.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.