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

Support Revoking Vault Token on Shutdown #67

Merged
merged 11 commits into from
Feb 25, 2020
22 changes: 20 additions & 2 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// TODO swap out 'github.com/mattbaird/jsonpatch' for 'github.com/evanphx/json-patch'

const (
DefaultVaultImage = "vault:1.3.1"
DefaultVaultImage = "vault:1.3.1"
DefaultVaultAuthPath = "auth/kubernetes"
)

Expand Down Expand Up @@ -52,9 +52,17 @@ type Agent struct {
PrePopulate bool

// PrePopulateOnly controls whether an init container is the _only_ container
//added to the request.
// added to the request.
PrePopulateOnly bool

// RevokeOnShutdown controls whether a sidecar container will attempt to revoke its Vault
// token on shutting down.
RevokeOnShutdown bool

// RevokeGrace controls after receiving the signal for pod
// termination that the container will attempt to revoke its own Vault token.
RevokeGrace uint64

// RequestsCPU is the requested minimum CPU amount required when being scheduled to deploy.
RequestsCPU string

Expand Down Expand Up @@ -194,6 +202,16 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro
return agent, err
}

agent.RevokeOnShutdown, err = agent.revokeOnShutdown()
if err != nil {
return agent, err
}

agent.RevokeGrace, err = agent.revokeGrace()
if err != nil {
return agent, err
}

agent.Vault.TLSSkipVerify, err = agent.tlsSkipVerify()
if err != nil {
return agent, err
Expand Down
31 changes: 31 additions & 0 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ const (
// AnnotationAgentRequestsMem sets the requested memory amount on the Vault Agent containers.
AnnotationAgentRequestsMem = "vault.hashicorp.com/agent-requests-mem"

// AnnotationAgentRevokeOnShutdown controls whether a sidecar container will revoke its
// own Vault token before shutting down. If you are using a custom agent template, you must
// make sure it's written to `/home/vault/.vault-token`. Only supported for sidecar containers.
AnnotationAgentRevokeOnShutdown = "vault.hashicorp.com/agent-revoke-on-shutdown"

// AnnotationAgentRevokeGrace sets the number of seconds after receiving the signal for pod
// termination that the container will attempt to revoke its own Vault token. Defaults to 5s.
AnnotationAgentRevokeGrace = "vault.hashicorp.com/agent-revoke-grace"

// AnnotationVaultService is the name of the Vault server. This can be overridden by the
// user but will be set by a flag on the deployment.
AnnotationVaultService = "vault.hashicorp.com/service"
Expand Down Expand Up @@ -173,6 +182,10 @@ func Init(pod *corev1.Pod, image, address, authPath, namespace string) error {
pod.ObjectMeta.Annotations[AnnotationAgentRequestsMem] = DefaultResourceRequestMem
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationAgentRevokeGrace]; !ok {
pod.ObjectMeta.Annotations[AnnotationAgentRevokeGrace] = DefaultRevokeGrace
}

return nil
}

Expand Down Expand Up @@ -234,6 +247,24 @@ func (a *Agent) prePopulateOnly() (bool, error) {
return strconv.ParseBool(raw)
}

func (a *Agent) revokeOnShutdown() (bool, error) {
raw, ok := a.Annotations[AnnotationAgentRevokeOnShutdown]
if !ok {
return false, nil
}

return strconv.ParseBool(raw)
}

func (a *Agent) revokeGrace() (uint64, error) {
raw, ok := a.Annotations[AnnotationAgentRevokeGrace]
if !ok {
return 0, nil
}

return strconv.ParseUint(raw, 10, 64)
}

func (a *Agent) tlsSkipVerify() (bool, error) {
raw, ok := a.Annotations[AnnotationVaultTLSSkipVerify]
if !ok {
Expand Down
18 changes: 18 additions & 0 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,24 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationVaultTLSSkipVerify, "tRuE", false},
{AnnotationVaultTLSSkipVerify, "fAlSe", false},
{AnnotationVaultTLSSkipVerify, "", false},

{AnnotationAgentRevokeOnShutdown, "true", true},
{AnnotationAgentRevokeOnShutdown, "false", true},
{AnnotationAgentRevokeOnShutdown, "TRUE", true},
{AnnotationAgentRevokeOnShutdown, "FALSE", true},
{AnnotationAgentRevokeOnShutdown, "0", true},
{AnnotationAgentRevokeOnShutdown, "1", true},
{AnnotationAgentRevokeOnShutdown, "t", true},
{AnnotationAgentRevokeOnShutdown, "f", true},
{AnnotationAgentRevokeOnShutdown, "tRuE", false},
{AnnotationAgentRevokeOnShutdown, "fAlSe", false},
{AnnotationAgentRevokeOnShutdown, "", false},

{AnnotationAgentRevokeGrace, "5", true},
{AnnotationAgentRevokeGrace, "0", true},
{AnnotationAgentRevokeGrace, "01", true},
{AnnotationAgentRevokeGrace, "-1", false},
{AnnotationAgentRevokeGrace, "foobar", false},
}

for i, tt := range tests {
Expand Down
4 changes: 2 additions & 2 deletions agent-inject/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
const (
DefaultTemplate = "{{ with secret \"%s\" }}{{ range $k, $v := .Data }}{{ $k }}: {{ $v }}\n{{ end }}{{ end }}"
PidFile = "/home/vault/.pid"
TokenFile = "/home/vault/.token"
TokenFile = "/home/vault/.vault-token"
)

// Config is the top level struct that composes a Vault Agent
Expand Down Expand Up @@ -104,7 +104,7 @@ func (a *Agent) newConfig(init bool) ([]byte, error) {
},
AutoAuth: &AutoAuth{
Method: &Method{
Type: "kubernetes",
Type: "kubernetes",
MountPath: a.Vault.AuthPath,
Config: map[string]interface{}{
"role": a.Vault.Role,
Expand Down
19 changes: 19 additions & 0 deletions agent-inject/agent/container_sidecar.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
DefaultResourceRequestCPU = "250m"
DefaultResourceRequestMem = "64Mi"
DefaultContainerArg = "echo ${VAULT_CONFIG?} | base64 -d > /tmp/config.json && vault agent -config=/tmp/config.json"
DefaultRevokeGrace = "5"
)

// ContainerSidecar creates a new container to be added
Expand Down Expand Up @@ -62,6 +63,8 @@ func (a *Agent) ContainerSidecar() (corev1.Container, error) {
return corev1.Container{}, err
}

lifecycle := a.createLifecycle()

return corev1.Container{
Name: "vault-agent",
Image: a.ImageName,
Expand All @@ -72,6 +75,7 @@ func (a *Agent) ContainerSidecar() (corev1.Container, error) {
RunAsGroup: pointerutil.Int64Ptr(1000),
RunAsNonRoot: pointerutil.BoolPtr(true),
},
Lifecycle: &lifecycle,
VolumeMounts: volumeMounts,
Command: []string{"/bin/sh", "-ec"},
Args: []string{arg},
Expand Down Expand Up @@ -124,3 +128,18 @@ func parseQuantity(raw string) (resource.Quantity, error) {

return resource.ParseQuantity(raw)
}

// This should only be run for a sidecar container
func (a *Agent) createLifecycle() corev1.Lifecycle {
lifecycle := corev1.Lifecycle{}

if a.RevokeOnShutdown {
lifecycle.PreStop = &corev1.Handler{
Exec: &corev1.ExecAction{
Command: []string{"/bin/sh", "-c", fmt.Sprintf("/bin/sleep %d && /bin/vault token revoke -self", a.RevokeGrace)},
},
}
}

return lifecycle
}
4 changes: 4 additions & 0 deletions agent-inject/agent/container_sidecar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ func TestContainerSidecar(t *testing.T) {
if container.Resources.Requests.Memory().String() != DefaultResourceRequestMem {
t.Errorf("resource memory requests value wrong, should have been %s, got %s", DefaultResourceLimitMem, container.Resources.Requests.Memory().String())
}

if container.Lifecycle.PreStop != nil {
t.Error("preStop hook should not be enabled by default")
}
}

func TestContainerSidecarConfigMap(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion agent-inject/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Handler struct {
// If this is false, injection is default.
RequireAnnotation bool
VaultAddress string
VaultAuthPath string
VaultAuthPath string
ImageVault string
Clientset *kubernetes.Clientset
Log hclog.Logger
Expand Down
14 changes: 7 additions & 7 deletions agent-inject/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestHandlerHandle(t *testing.T) {

{
"injection disabled",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath:"kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
Expand All @@ -108,7 +108,7 @@ func TestHandlerHandle(t *testing.T) {

{
"basic pod injection",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath:"kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
Expand Down Expand Up @@ -148,7 +148,7 @@ func TestHandlerHandle(t *testing.T) {

{
"configmap pod injection",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath:"kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
Expand Down Expand Up @@ -192,7 +192,7 @@ func TestHandlerHandle(t *testing.T) {

{
"tls pod injection",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath:"kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
Expand Down Expand Up @@ -241,7 +241,7 @@ func TestHandlerHandle(t *testing.T) {

{
"tls no configmap pod injection",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath:"kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
Expand Down Expand Up @@ -286,7 +286,7 @@ func TestHandlerHandle(t *testing.T) {

{
"tls no configmap no init pod injection",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath:"kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
Expand Down Expand Up @@ -328,7 +328,7 @@ func TestHandlerHandle(t *testing.T) {

{
"tls no configmap init only pod injection",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath:"kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
Expand Down