-
-
Notifications
You must be signed in to change notification settings - Fork 185
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding support for AppRole vault auth backend
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
- Loading branch information
1 parent
0d97dd7
commit 9bc97b3
Showing
8 changed files
with
216 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package vault | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
"time" | ||
) | ||
|
||
// AppRoleAuthStrategy - an AuthStrategy that uses Vault's approle authentication backend. | ||
type AppRoleAuthStrategy struct { | ||
RoleID string `json:"role_id"` | ||
SecretID string `json:"secret_id"` | ||
Mount string `json:"-"` | ||
hc *http.Client | ||
} | ||
|
||
// NewAppRoleAuthStrategy - create an AuthStrategy that uses Vault's approle auth | ||
// backend. | ||
func NewAppRoleAuthStrategy() *AppRoleAuthStrategy { | ||
roleID := os.Getenv("VAULT_ROLE_ID") | ||
secretID := os.Getenv("VAULT_SECRET_ID") | ||
mount := os.Getenv("VAULT_AUTH_APPROLE_MOUNT") | ||
if mount == "" { | ||
mount = "approle" | ||
} | ||
if roleID != "" && secretID != "" { | ||
return &AppRoleAuthStrategy{roleID, secretID, mount, nil} | ||
} | ||
return nil | ||
} | ||
|
||
// GetHTTPClient configures the HTTP client with a timeout | ||
func (a *AppRoleAuthStrategy) GetHTTPClient() *http.Client { | ||
if a.hc == nil { | ||
a.hc = &http.Client{Timeout: time.Second * 5} | ||
} | ||
return a.hc | ||
} | ||
|
||
// SetToken is a no-op for AppRoleAuthStrategy as a token hasn't been acquired yet | ||
func (a *AppRoleAuthStrategy) SetToken(req *http.Request) { | ||
// no-op | ||
} | ||
|
||
// Do wraps http.Client.Do | ||
func (a *AppRoleAuthStrategy) Do(req *http.Request) (*http.Response, error) { | ||
hc := a.GetHTTPClient() | ||
return hc.Do(req) | ||
} | ||
|
||
// GetToken - log in to the approle auth backend and return the client token | ||
func (a *AppRoleAuthStrategy) GetToken(addr *url.URL) (string, error) { | ||
buf := new(bytes.Buffer) | ||
json.NewEncoder(buf).Encode(&a) | ||
|
||
u := &url.URL{} | ||
*u = *addr | ||
u.Path = "/v1/auth/" + a.Mount + "/login" | ||
res, err := requestAndFollow(a, "POST", u, buf.Bytes()) | ||
if err != nil { | ||
return "", err | ||
} | ||
response := &AppRoleAuthResponse{} | ||
err = json.NewDecoder(res.Body).Decode(response) | ||
res.Body.Close() | ||
if err != nil { | ||
return "", err | ||
} | ||
if res.StatusCode != 200 { | ||
err := fmt.Errorf("Unexpected HTTP status %d on AppRole login to %s: %s", res.StatusCode, u, response) | ||
return "", err | ||
} | ||
return response.Auth.ClientToken, nil | ||
} | ||
|
||
// Revokable - | ||
func (a *AppRoleAuthStrategy) Revokable() bool { | ||
return true | ||
} | ||
|
||
func (a *AppRoleAuthStrategy) String() string { | ||
return fmt.Sprintf("role_id: %s, secret_id: %s, mount: %s", a.RoleID, a.SecretID, a.Mount) | ||
} | ||
|
||
// AppRoleAuthResponse - the Auth response from /v1/auth/approle/login | ||
type AppRoleAuthResponse struct { | ||
Auth struct { | ||
ClientToken string `json:"client_token"` | ||
LeaseDuration int64 `json:"lease_duration"` | ||
Metadata struct{} `json:"metadata"` | ||
Policies []string `json:"policies"` | ||
Renewable bool `json:"renewable"` | ||
} `json:"auth"` | ||
} | ||
|
||
func (a *AppRoleAuthResponse) String() string { | ||
buf := new(bytes.Buffer) | ||
json.NewEncoder(buf).Encode(&a) | ||
return string(buf.Bytes()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package vault | ||
|
||
import ( | ||
"net/url" | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNewAppRoleAuthStrategy(t *testing.T) { | ||
defer os.Unsetenv("VAULT_ROLE_ID") | ||
defer os.Unsetenv("VAULT_SECRET_ID") | ||
defer os.Unsetenv("VAULT_AUTH_APPROLE_MOUNT") | ||
|
||
os.Unsetenv("VAULT_ROLE_ID") | ||
os.Unsetenv("VAULT_SECRET_ID") | ||
assert.Nil(t, NewAppRoleAuthStrategy()) | ||
|
||
os.Setenv("VAULT_ROLE_ID", "foo") | ||
assert.Nil(t, NewAppRoleAuthStrategy()) | ||
|
||
os.Unsetenv("VAULT_ROLE_ID") | ||
os.Setenv("VAULT_SECRET_ID", "bar") | ||
assert.Nil(t, NewAppRoleAuthStrategy()) | ||
|
||
os.Setenv("VAULT_ROLE_ID", "foo") | ||
os.Setenv("VAULT_SECRET_ID", "bar") | ||
auth := NewAppRoleAuthStrategy() | ||
assert.Equal(t, "foo", auth.RoleID) | ||
assert.Equal(t, "bar", auth.SecretID) | ||
assert.Equal(t, "approle", auth.Mount) | ||
|
||
os.Setenv("VAULT_ROLE_ID", "baz") | ||
os.Setenv("VAULT_SECRET_ID", "qux") | ||
os.Setenv("VAULT_AUTH_APPROLE_MOUNT", "quux") | ||
auth = NewAppRoleAuthStrategy() | ||
assert.Equal(t, "baz", auth.RoleID) | ||
assert.Equal(t, "qux", auth.SecretID) | ||
assert.Equal(t, "quux", auth.Mount) | ||
} | ||
|
||
func TestGetToken_AppRoleErrorsGivenNetworkError(t *testing.T) { | ||
server, client := setupErrorHTTP() | ||
defer server.Close() | ||
|
||
vaultURL, _ := url.Parse("http://vault:8200") | ||
|
||
auth := &AppRoleAuthStrategy{"foo", "bar", "approle", client} | ||
_, err := auth.GetToken(vaultURL) | ||
assert.Error(t, err) | ||
} | ||
|
||
func TestGetToken_AppRoleErrorsGivenHTTPErrorStatus(t *testing.T) { | ||
server, client := setupHTTP(500, "application/json; charset=utf-8", `{}`) | ||
defer server.Close() | ||
|
||
vaultURL, _ := url.Parse("http://vault:8200") | ||
|
||
auth := &AppRoleAuthStrategy{"foo", "bar", "approle", client} | ||
_, err := auth.GetToken(vaultURL) | ||
assert.Error(t, err) | ||
} | ||
|
||
func TestGetToken_AppRoleErrorsGivenBadJSON(t *testing.T) { | ||
server, client := setupHTTP(200, "application/json; charset=utf-8", `{`) | ||
defer server.Close() | ||
|
||
vaultURL, _ := url.Parse("http://vault:8200") | ||
|
||
auth := &AppRoleAuthStrategy{"foo", "bar", "approle", client} | ||
_, err := auth.GetToken(vaultURL) | ||
assert.Error(t, err) | ||
} | ||
|
||
func TestGetToken_AppRole(t *testing.T) { | ||
server, client := setupHTTP(200, "application/json; charset=utf-8", `{"auth": {"client_token": "baz"}}`) | ||
defer server.Close() | ||
|
||
vaultURL, _ := url.Parse("http://vault:8200") | ||
|
||
auth := &AppRoleAuthStrategy{"foo", "bar", "approle", client} | ||
token, err := auth.GetToken(vaultURL) | ||
assert.NoError(t, err) | ||
|
||
assert.Equal(t, "baz", token) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters