diff options
author | 2017-08-31 11:59:47 +0800 | |
---|---|---|
committer | 2017-08-31 12:00:09 +0800 | |
commit | c0f3b093c704da85252044b3a177dbabab63c49a (patch) | |
tree | f6cb5d85315c307bcf4984ac04e76e84b9abeac6 /kube2msb/src/vendor/github.com/coreos/go-oidc/key | |
parent | c1737d2abac61511e00f388538779d67464b8a98 (diff) |
add vendor package
Issue-Id: OOM-61
Change-Id: I251336e3b711b14f8ae9a8b0bf6055011a1d9bc8
Signed-off-by: HuabingZhao <zhao.huabing@zte.com.cn>
Diffstat (limited to 'kube2msb/src/vendor/github.com/coreos/go-oidc/key')
5 files changed, 563 insertions, 0 deletions
diff --git a/kube2msb/src/vendor/github.com/coreos/go-oidc/key/key.go b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/key.go new file mode 100644 index 0000000..d0142a9 --- /dev/null +++ b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/key.go @@ -0,0 +1,153 @@ +package key + +import ( + "crypto/rand" + "crypto/rsa" + "encoding/base64" + "encoding/json" + "math/big" + "time" + + "github.com/coreos/go-oidc/jose" +) + +func NewPublicKey(jwk jose.JWK) *PublicKey { + return &PublicKey{jwk: jwk} +} + +type PublicKey struct { + jwk jose.JWK +} + +func (k *PublicKey) MarshalJSON() ([]byte, error) { + return json.Marshal(&k.jwk) +} + +func (k *PublicKey) UnmarshalJSON(data []byte) error { + var jwk jose.JWK + if err := json.Unmarshal(data, &jwk); err != nil { + return err + } + k.jwk = jwk + return nil +} + +func (k *PublicKey) ID() string { + return k.jwk.ID +} + +func (k *PublicKey) Verifier() (jose.Verifier, error) { + return jose.NewVerifierRSA(k.jwk) +} + +type PrivateKey struct { + KeyID string + PrivateKey *rsa.PrivateKey +} + +func (k *PrivateKey) ID() string { + return k.KeyID +} + +func (k *PrivateKey) Signer() jose.Signer { + return jose.NewSignerRSA(k.ID(), *k.PrivateKey) +} + +func (k *PrivateKey) JWK() jose.JWK { + return jose.JWK{ + ID: k.KeyID, + Type: "RSA", + Alg: "RS256", + Use: "sig", + Exponent: k.PrivateKey.PublicKey.E, + Modulus: k.PrivateKey.PublicKey.N, + } +} + +type KeySet interface { + ExpiresAt() time.Time +} + +type PublicKeySet struct { + keys []PublicKey + index map[string]*PublicKey + expiresAt time.Time +} + +func NewPublicKeySet(jwks []jose.JWK, exp time.Time) *PublicKeySet { + keys := make([]PublicKey, len(jwks)) + index := make(map[string]*PublicKey) + for i, jwk := range jwks { + keys[i] = *NewPublicKey(jwk) + index[keys[i].ID()] = &keys[i] + } + return &PublicKeySet{ + keys: keys, + index: index, + expiresAt: exp, + } +} + +func (s *PublicKeySet) ExpiresAt() time.Time { + return s.expiresAt +} + +func (s *PublicKeySet) Keys() []PublicKey { + return s.keys +} + +func (s *PublicKeySet) Key(id string) *PublicKey { + return s.index[id] +} + +type PrivateKeySet struct { + keys []*PrivateKey + ActiveKeyID string + expiresAt time.Time +} + +func NewPrivateKeySet(keys []*PrivateKey, exp time.Time) *PrivateKeySet { + return &PrivateKeySet{ + keys: keys, + ActiveKeyID: keys[0].ID(), + expiresAt: exp.UTC(), + } +} + +func (s *PrivateKeySet) Keys() []*PrivateKey { + return s.keys +} + +func (s *PrivateKeySet) ExpiresAt() time.Time { + return s.expiresAt +} + +func (s *PrivateKeySet) Active() *PrivateKey { + for i, k := range s.keys { + if k.ID() == s.ActiveKeyID { + return s.keys[i] + } + } + + return nil +} + +type GeneratePrivateKeyFunc func() (*PrivateKey, error) + +func GeneratePrivateKey() (*PrivateKey, error) { + pk, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, err + } + + k := PrivateKey{ + KeyID: base64BigInt(pk.PublicKey.N), + PrivateKey: pk, + } + + return &k, nil +} + +func base64BigInt(b *big.Int) string { + return base64.URLEncoding.EncodeToString(b.Bytes()) +} diff --git a/kube2msb/src/vendor/github.com/coreos/go-oidc/key/manager.go b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/manager.go new file mode 100644 index 0000000..476ab6a --- /dev/null +++ b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/manager.go @@ -0,0 +1,99 @@ +package key + +import ( + "errors" + "time" + + "github.com/jonboulle/clockwork" + + "github.com/coreos/go-oidc/jose" + "github.com/coreos/pkg/health" +) + +type PrivateKeyManager interface { + ExpiresAt() time.Time + Signer() (jose.Signer, error) + JWKs() ([]jose.JWK, error) + PublicKeys() ([]PublicKey, error) + + WritableKeySetRepo + health.Checkable +} + +func NewPrivateKeyManager() PrivateKeyManager { + return &privateKeyManager{ + clock: clockwork.NewRealClock(), + } +} + +type privateKeyManager struct { + keySet *PrivateKeySet + clock clockwork.Clock +} + +func (m *privateKeyManager) ExpiresAt() time.Time { + if m.keySet == nil { + return m.clock.Now().UTC() + } + + return m.keySet.ExpiresAt() +} + +func (m *privateKeyManager) Signer() (jose.Signer, error) { + if err := m.Healthy(); err != nil { + return nil, err + } + + return m.keySet.Active().Signer(), nil +} + +func (m *privateKeyManager) JWKs() ([]jose.JWK, error) { + if err := m.Healthy(); err != nil { + return nil, err + } + + keys := m.keySet.Keys() + jwks := make([]jose.JWK, len(keys)) + for i, k := range keys { + jwks[i] = k.JWK() + } + return jwks, nil +} + +func (m *privateKeyManager) PublicKeys() ([]PublicKey, error) { + jwks, err := m.JWKs() + if err != nil { + return nil, err + } + keys := make([]PublicKey, len(jwks)) + for i, jwk := range jwks { + keys[i] = *NewPublicKey(jwk) + } + return keys, nil +} + +func (m *privateKeyManager) Healthy() error { + if m.keySet == nil { + return errors.New("private key manager uninitialized") + } + + if len(m.keySet.Keys()) == 0 { + return errors.New("private key manager zero keys") + } + + if m.keySet.ExpiresAt().Before(m.clock.Now().UTC()) { + return errors.New("private key manager keys expired") + } + + return nil +} + +func (m *privateKeyManager) Set(keySet KeySet) error { + privKeySet, ok := keySet.(*PrivateKeySet) + if !ok { + return errors.New("unable to cast to PrivateKeySet") + } + + m.keySet = privKeySet + return nil +} diff --git a/kube2msb/src/vendor/github.com/coreos/go-oidc/key/repo.go b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/repo.go new file mode 100644 index 0000000..1acdeb3 --- /dev/null +++ b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/repo.go @@ -0,0 +1,55 @@ +package key + +import ( + "errors" + "sync" +) + +var ErrorNoKeys = errors.New("no keys found") + +type WritableKeySetRepo interface { + Set(KeySet) error +} + +type ReadableKeySetRepo interface { + Get() (KeySet, error) +} + +type PrivateKeySetRepo interface { + WritableKeySetRepo + ReadableKeySetRepo +} + +func NewPrivateKeySetRepo() PrivateKeySetRepo { + return &memPrivateKeySetRepo{} +} + +type memPrivateKeySetRepo struct { + mu sync.RWMutex + pks PrivateKeySet +} + +func (r *memPrivateKeySetRepo) Set(ks KeySet) error { + pks, ok := ks.(*PrivateKeySet) + if !ok { + return errors.New("unable to cast to PrivateKeySet") + } else if pks == nil { + return errors.New("nil KeySet") + } + + r.mu.Lock() + defer r.mu.Unlock() + + r.pks = *pks + return nil +} + +func (r *memPrivateKeySetRepo) Get() (KeySet, error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if r.pks.keys == nil { + return nil, ErrorNoKeys + } + return KeySet(&r.pks), nil +} diff --git a/kube2msb/src/vendor/github.com/coreos/go-oidc/key/rotate.go b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/rotate.go new file mode 100644 index 0000000..9c5508b --- /dev/null +++ b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/rotate.go @@ -0,0 +1,165 @@ +package key + +import ( + "errors" + "time" + + "github.com/coreos/pkg/capnslog" + ptime "github.com/coreos/pkg/timeutil" + "github.com/jonboulle/clockwork" +) + +var ( + log = capnslog.NewPackageLogger("github.com/coreos/go-oidc", "key") + + ErrorPrivateKeysExpired = errors.New("private keys have expired") +) + +func NewPrivateKeyRotator(repo PrivateKeySetRepo, ttl time.Duration) *PrivateKeyRotator { + return &PrivateKeyRotator{ + repo: repo, + ttl: ttl, + + keep: 2, + generateKey: GeneratePrivateKey, + clock: clockwork.NewRealClock(), + } +} + +type PrivateKeyRotator struct { + repo PrivateKeySetRepo + generateKey GeneratePrivateKeyFunc + clock clockwork.Clock + keep int + ttl time.Duration +} + +func (r *PrivateKeyRotator) expiresAt() time.Time { + return r.clock.Now().UTC().Add(r.ttl) +} + +func (r *PrivateKeyRotator) Healthy() error { + pks, err := r.privateKeySet() + if err != nil { + return err + } + + if r.clock.Now().After(pks.ExpiresAt()) { + return ErrorPrivateKeysExpired + } + + return nil +} + +func (r *PrivateKeyRotator) privateKeySet() (*PrivateKeySet, error) { + ks, err := r.repo.Get() + if err != nil { + return nil, err + } + + pks, ok := ks.(*PrivateKeySet) + if !ok { + return nil, errors.New("unable to cast to PrivateKeySet") + } + return pks, nil +} + +func (r *PrivateKeyRotator) nextRotation() (time.Duration, error) { + pks, err := r.privateKeySet() + if err == ErrorNoKeys { + log.Infof("No keys in private key set; must rotate immediately") + return 0, nil + } + if err != nil { + return 0, err + } + + now := r.clock.Now() + + // Ideally, we want to rotate after half the TTL has elapsed. + idealRotationTime := pks.ExpiresAt().Add(-r.ttl / 2) + + // If we are past the ideal rotation time, rotate immediatly. + return max(0, idealRotationTime.Sub(now)), nil +} + +func max(a, b time.Duration) time.Duration { + if a > b { + return a + } + return b +} + +func (r *PrivateKeyRotator) Run() chan struct{} { + attempt := func() { + k, err := r.generateKey() + if err != nil { + log.Errorf("Failed generating signing key: %v", err) + return + } + + exp := r.expiresAt() + if err := rotatePrivateKeys(r.repo, k, r.keep, exp); err != nil { + log.Errorf("Failed key rotation: %v", err) + return + } + + log.Infof("Rotated signing keys: id=%s expiresAt=%s", k.ID(), exp) + } + + stop := make(chan struct{}) + go func() { + for { + var nextRotation time.Duration + var sleep time.Duration + var err error + for { + if nextRotation, err = r.nextRotation(); err == nil { + break + } + sleep = ptime.ExpBackoff(sleep, time.Minute) + log.Errorf("error getting nextRotation, retrying in %v: %v", sleep, err) + time.Sleep(sleep) + } + + log.Infof("will rotate keys in %v", nextRotation) + select { + case <-r.clock.After(nextRotation): + attempt() + case <-stop: + return + } + } + }() + + return stop +} + +func rotatePrivateKeys(repo PrivateKeySetRepo, k *PrivateKey, keep int, exp time.Time) error { + ks, err := repo.Get() + if err != nil && err != ErrorNoKeys { + return err + } + + var keys []*PrivateKey + if ks != nil { + pks, ok := ks.(*PrivateKeySet) + if !ok { + return errors.New("unable to cast to PrivateKeySet") + } + keys = pks.Keys() + } + + keys = append([]*PrivateKey{k}, keys...) + if l := len(keys); l > keep { + keys = keys[0:keep] + } + + nks := PrivateKeySet{ + keys: keys, + ActiveKeyID: k.ID(), + expiresAt: exp, + } + + return repo.Set(KeySet(&nks)) +} diff --git a/kube2msb/src/vendor/github.com/coreos/go-oidc/key/sync.go b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/sync.go new file mode 100644 index 0000000..e8d5d03 --- /dev/null +++ b/kube2msb/src/vendor/github.com/coreos/go-oidc/key/sync.go @@ -0,0 +1,91 @@ +package key + +import ( + "errors" + "time" + + "github.com/jonboulle/clockwork" + + "github.com/coreos/pkg/timeutil" +) + +func NewKeySetSyncer(r ReadableKeySetRepo, w WritableKeySetRepo) *KeySetSyncer { + return &KeySetSyncer{ + readable: r, + writable: w, + clock: clockwork.NewRealClock(), + } +} + +type KeySetSyncer struct { + readable ReadableKeySetRepo + writable WritableKeySetRepo + clock clockwork.Clock +} + +func (s *KeySetSyncer) Run() chan struct{} { + stop := make(chan struct{}) + go func() { + var failing bool + var next time.Duration + for { + exp, err := syncKeySet(s.readable, s.writable, s.clock) + if err != nil || exp == 0 { + if !failing { + failing = true + next = time.Second + } else { + next = timeutil.ExpBackoff(next, time.Minute) + } + if exp == 0 { + log.Errorf("Synced to already expired key set, retrying in %v: %v", next, err) + + } else { + log.Errorf("Failed syncing key set, retrying in %v: %v", next, err) + } + } else { + failing = false + next = exp / 2 + log.Infof("Synced key set, checking again in %v", next) + } + + select { + case <-s.clock.After(next): + continue + case <-stop: + return + } + } + }() + + return stop +} + +func Sync(r ReadableKeySetRepo, w WritableKeySetRepo) (time.Duration, error) { + return syncKeySet(r, w, clockwork.NewRealClock()) +} + +// syncKeySet copies the keyset from r to the KeySet at w and returns the duration in which the KeySet will expire. +// If keyset has already expired, returns a zero duration. +func syncKeySet(r ReadableKeySetRepo, w WritableKeySetRepo, clock clockwork.Clock) (exp time.Duration, err error) { + var ks KeySet + ks, err = r.Get() + if err != nil { + return + } + + if ks == nil { + err = errors.New("no source KeySet") + return + } + + if err = w.Set(ks); err != nil { + return + } + + now := clock.Now() + if ks.ExpiresAt().After(now) { + exp = ks.ExpiresAt().Sub(now) + } + return +} |