forked from TrueCloudLab/certificates
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:
parent
9572c62520
commit
9e5762fe06
5 changed files with 20 additions and 4 deletions
|
@ -173,6 +173,9 @@ func (a *Authority) AuthorizeAdminToken(r *http.Request, token string) (*linkedc
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseToken stores the token to protect against reuse.
|
// 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 {
|
func (a *Authority) UseToken(token string, prov provisioner.Interface) error {
|
||||||
if reuseKey, err := prov.GetTokenID(token); err == nil {
|
if reuseKey, err := prov.GetTokenID(token); err == nil {
|
||||||
if reuseKey == "" {
|
if reuseKey == "" {
|
||||||
|
|
|
@ -131,9 +131,10 @@ func (p *Azure) GetTokenID(token string) (string, error) {
|
||||||
return "", errors.Wrap(err, "error verifying claims")
|
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 {
|
if p.DisableTrustOnFirstUse {
|
||||||
return claims.ID, nil
|
return "", ErrAllowTokenReuse
|
||||||
}
|
}
|
||||||
|
|
||||||
sum := sha256.Sum256([]byte(claims.XMSMirID))
|
sum := sha256.Sum256([]byte(claims.XMSMirID))
|
||||||
|
|
|
@ -72,7 +72,7 @@ func TestAzure_GetTokenID(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, w1, false},
|
{"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 token", p1, args{"bad-token"}, "", true},
|
||||||
{"fail claims", p1, args{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ey.fooo"}, "", true},
|
{"fail claims", p1, args{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ey.fooo"}, "", true},
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
stderrors "errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -32,6 +33,17 @@ type Interface interface {
|
||||||
AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error)
|
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.
|
// Audiences stores all supported audiences by request type.
|
||||||
type Audiences struct {
|
type Audiences struct {
|
||||||
Sign []string
|
Sign []string
|
||||||
|
|
|
@ -366,7 +366,7 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error
|
||||||
}
|
}
|
||||||
rci.ProvisionerID = p.GetID()
|
rci.ProvisionerID = p.GetID()
|
||||||
rci.TokenID, err = p.GetTokenID(revokeOpts.OTT)
|
rci.TokenID, err = p.GetTokenID(revokeOpts.OTT)
|
||||||
if err != nil {
|
if err != nil && !errors.Is(err, provisioner.ErrAllowTokenReuse) {
|
||||||
return errs.Wrap(http.StatusInternalServerError, err,
|
return errs.Wrap(http.StatusInternalServerError, err,
|
||||||
"authority.Revoke; could not get ID for token")
|
"authority.Revoke; could not get ID for token")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue