Allow the reuse of azure token if DisableTrustOnFirstUse is true

Azure caches tokens for 24h and we cannot issue a new certificate
for the same instance in that period of time.

The meaning of this parameter is to allow the signing of multiple
certificate in one instance. This is possible in GCP, because we
get a new token, and is possible in AWS because we can generate
a new one. On Azure there was no other way to do it unless you
wait for 24h.

Fixes #656
This commit is contained in:
Mariano Cano 2021-08-11 11:50:54 -07:00
parent 9572c62520
commit 9e5762fe06
5 changed files with 20 additions and 4 deletions

View file

@ -173,6 +173,9 @@ func (a *Authority) AuthorizeAdminToken(r *http.Request, token string) (*linkedc
}
// UseToken stores the token to protect against reuse.
//
// This method currently ignores any error coming from the GetTokenID, but it
// should specifically ignore the error provisioner.ErrAllowTokenReuse.
func (a *Authority) UseToken(token string, prov provisioner.Interface) error {
if reuseKey, err := prov.GetTokenID(token); err == nil {
if reuseKey == "" {

View file

@ -131,9 +131,10 @@ func (p *Azure) GetTokenID(token string) (string, error) {
return "", errors.Wrap(err, "error verifying claims")
}
// If TOFU is disabled create return the token kid
// If TOFU is disabled then allow token re-use. Azure caches the token for
// 24h and without allowing the re-use we cannot use it twice.
if p.DisableTrustOnFirstUse {
return claims.ID, nil
return "", ErrAllowTokenReuse
}
sum := sha256.Sum256([]byte(claims.XMSMirID))

View file

@ -72,7 +72,7 @@ func TestAzure_GetTokenID(t *testing.T) {
wantErr bool
}{
{"ok", p1, args{t1}, w1, false},
{"ok no TOFU", p2, args{t2}, "the-jti", false},
{"ok no TOFU", p2, args{t2}, "", true},
{"fail token", p1, args{"bad-token"}, "", true},
{"fail claims", p1, args{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ey.fooo"}, "", true},
}

View file

@ -4,6 +4,7 @@ import (
"context"
"crypto/x509"
"encoding/json"
stderrors "errors"
"net/url"
"regexp"
"strings"
@ -32,6 +33,17 @@ type Interface interface {
AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error)
}
// ErrAllowTokenReuse is an error that is returned by provisioners that allows
// the reuse of tokens.
//
// This is for example returned by the Azure provisioner when
// DisableTrustOnFirstUse is set to true. For AWS and GCP DisableTrustOnFirst
// use means that we allow the re-use of a token coming from a specific
// instance, but in these providers we can always get a new token, but because
// Azure caches the token for up to 24h we should add a mechanism to allow the
// re-use.
var ErrAllowTokenReuse = stderrors.New("allow token reuse")
// Audiences stores all supported audiences by request type.
type Audiences struct {
Sign []string

View file

@ -366,7 +366,7 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error
}
rci.ProvisionerID = p.GetID()
rci.TokenID, err = p.GetTokenID(revokeOpts.OTT)
if err != nil {
if err != nil && !errors.Is(err, provisioner.ErrAllowTokenReuse) {
return errs.Wrap(http.StatusInternalServerError, err,
"authority.Revoke; could not get ID for token")
}