Expose all service-account keys through OIDC

This commit is contained in:
John Gardiner Myers 2021-04-11 21:27:21 -07:00
parent ed1f6ff79e
commit 3127dacc0c
3 changed files with 32 additions and 44 deletions

View File

@ -219,7 +219,8 @@ func (b *BootstrapScriptBuilder) ResourceNodeUp(c *fi.ModelBuilderContext, ig *k
ig: ig,
builder: b,
caTask: caTask,
ca: caTask.Certificate(),
// TODO: use caTask.Keyset() and expose all CA certificates
ca: caTask.Certificate(),
}
task.resource.Task = task
c.AddTask(task)

View File

@ -22,9 +22,9 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"io"
"sort"
"gopkg.in/square/go-jose.v2"
"k8s.io/kops/pkg/apis/kops"
@ -128,38 +128,32 @@ func (o *OIDCKeys) GetDependencies(tasks map[string]fi.Task) []fi.Task {
}
}
func (o *OIDCKeys) Open() (io.Reader, error) {
keyset := o.SigningKey.Keyset()
var keys []jose.JSONWebKey
certBytes, err := fi.ResourceAsBytes(o.SigningKey.Certificate())
if err != nil {
return nil, fmt.Errorf("failed to get cert: %w", err)
}
block, _ := pem.Decode(certBytes)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse cert: %w", err)
}
for _, item := range keyset.Items {
publicKey := item.Certificate.PublicKey
publicKeyDERBytes, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return nil, fmt.Errorf("failed to serialize public key to DER format: %v", err)
}
publicKey := cert.PublicKey
hasher := crypto.SHA256.New()
hasher.Write(publicKeyDERBytes)
publicKeyDERHash := hasher.Sum(nil)
publicKeyDERBytes, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return nil, fmt.Errorf("failed to serialize public key to DER format: %v", err)
}
keyID := base64.RawURLEncoding.EncodeToString(publicKeyDERHash)
hasher := crypto.SHA256.New()
hasher.Write(publicKeyDERBytes)
publicKeyDERHash := hasher.Sum(nil)
keyID := base64.RawURLEncoding.EncodeToString(publicKeyDERHash)
keys := []jose.JSONWebKey{
{
keys = append(keys, jose.JSONWebKey{
Key: publicKey,
KeyID: keyID,
Algorithm: string(jose.RS256),
Use: "sig",
},
})
}
sort.Slice(keys, func(i, j int) bool {
return keys[i].KeyID < keys[j].KeyID
})
keyResponse := KeyResponse{Keys: keys}
jsonBytes, err := json.MarshalIndent(keyResponse, "", "")

View File

@ -17,7 +17,6 @@ limitations under the License.
package fitasks
import (
"crypto/sha1"
"crypto/x509/pkix"
"fmt"
"sort"
@ -46,8 +45,8 @@ type Keypair struct {
// LegacyFormat is whether the keypair is stored in a legacy format.
LegacyFormat bool `json:"oldFormat"`
certificate *fi.TaskDependentResource
certificateSHA1Fingerprint *fi.TaskDependentResource
certificate *fi.TaskDependentResource
keyset *fi.Keyset
}
var _ fi.HasCheckExisting = &Keypair{}
@ -103,7 +102,7 @@ func (e *Keypair) Find(c *fi.Context) (*Keypair, error) {
// Avoid spurious changes
actual.Lifecycle = e.Lifecycle
if err := e.setResources(cert); err != nil {
if err := e.setResources(keyset); err != nil {
return nil, fmt.Errorf("error setting resources: %v", err)
}
@ -233,18 +232,19 @@ func (_ *Keypair) Render(c *fi.Context, a, e, changes *Keypair) error {
PrivateKey: privateKey,
}
err = c.Keystore.StoreKeypair(name, &fi.Keyset{
keyset = &fi.Keyset{
LegacyFormat: false,
Items: map[string]*fi.KeysetItem{
serialString: ki,
},
Primary: ki,
})
}
err = c.Keystore.StoreKeypair(name, keyset)
if err != nil {
return err
}
if err := e.setResources(cert); err != nil {
if err := e.setResources(keyset); err != nil {
return fmt.Errorf("error setting resources: %v", err)
}
@ -308,30 +308,23 @@ func (e *Keypair) ensureResources() {
if e.certificate == nil {
e.certificate = &fi.TaskDependentResource{Task: e}
}
if e.certificateSHA1Fingerprint == nil {
e.certificateSHA1Fingerprint = &fi.TaskDependentResource{Task: e}
}
}
func (e *Keypair) setResources(cert *pki.Certificate) error {
func (e *Keypair) setResources(keyset *fi.Keyset) error {
e.ensureResources()
s, err := cert.AsString()
s, err := keyset.Primary.Certificate.AsString()
if err != nil {
return err
}
e.certificate.Resource = fi.NewStringResource(s)
fingerprint := sha1.Sum(cert.Certificate.Raw)
hex := fmt.Sprintf("%x", fingerprint)
e.certificateSHA1Fingerprint.Resource = fi.NewStringResource(hex)
e.keyset = keyset
return nil
}
func (e *Keypair) CertificateSHA1Fingerprint() fi.Resource {
e.ensureResources()
return e.certificateSHA1Fingerprint
func (e *Keypair) Keyset() *fi.Keyset {
return e.keyset
}
func (e *Keypair) Certificate() fi.Resource {