teleport/lib/jwt/jwk.go
Marco André Dinis f3a5d9695e
Integrations: AWS OIDC - ListDatabases action (#24460)
* AWSOIDC Integration: ListDatabases

This PR adds a new Action for the AWSOIDC Integration: ListDatabases
The goal of this action is to provide the User a list of RDS Databases
from which the User will pick one to be added as a Teleport Database
Resource.
This way, the user doesn't need to copy/paste DB name, endpoints and
labels.

Before being able to call this action, the User has to set up an AWS
OIDC integration.

How does it work:
```
                    Client (web app)
                     │     ▲
                     │     │4. Returns list of DBs
 1. List Databases   │     │   (name, tags, status, endpoint)
                     │     │
                     │     │
                     │     │
                     │     │
                     ▼     │       3. rds.DescribeDBInstances
               ┌───────────┴────┐     (auth: token)                ┌─────────┐
               │                ├─────────────────────────────────►│         │
               │ Teleport Proxy │                                  │   AWS   │
               │                │     3.1. Get OIDC Config         │         │
               │                │◄─────────────────────────────────┤         │
               │                │     3.2. Get RSA Public Key      │         │
               │                │◄─────────────────────────────────┤         ├─────────┐ 3.3.
               │                │                                  │         │         │Validates token signature
               │                │                                  │         │         │with received public key
               │                │   3.4 Returns list of DBs        │         │◄────────┘
               │                │◄─────────────────────────────────┤         │
               └─┬──────────────┘                                  └─────────┘
                 │
                 │  2. Sign Token
                 │
                 ▼
              ┌───────────────────┐
              │                   │
              │   Teleport Auth   │
              │  RSA Private Key  │
              └───────────────────┘

```

* add resource and account ids to DB resource

* move api namespaces

* use types.Database instead of custom database format

* add database uri

* fix comments and rate limiter

* test name override when converting RDS V2 DBs

* fix webapi database URI field

* TestClusterDatabasesGet: add parallel
2023-04-19 15:42:53 +00:00

98 lines
2.9 KiB
Go

/*
Copyright 2020 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package jwt
import (
"crypto"
"crypto/rsa"
"encoding/base64"
"math/big"
"github.com/gravitational/trace"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/utils"
)
// JWK is a JSON Web Key, described in detail in RFC 7517.
type JWK struct {
// KeyType is the type of asymmetric key used.
KeyType string `json:"kty"`
// Algorithm used to sign.
Algorithm string `json:"alg"`
// N is the modulus of the public key.
N string `json:"n"`
// E is the exponent of the public key.
E string `json:"e"`
// Use identifies the intended use of the public key.
// This field is required for the AWS OIDC Integration.
// https://www.rfc-editor.org/rfc/rfc7517#section-4.2
Use string `json:"use"`
// KeyID identifies the key to use.
// This field is required (even if empty) for the AWS OIDC Integration.
// https://www.rfc-editor.org/rfc/rfc7517#section-4.5
KeyID string `json:"kid"`
}
// MarshalJWK will marshal a supported public key into JWK format.
func MarshalJWK(bytes []byte) (JWK, error) {
// Parse the public key and validate type.
p, err := utils.ParsePublicKey(bytes)
if err != nil {
return JWK{}, trace.Wrap(err)
}
publicKey, ok := p.(*rsa.PublicKey)
if !ok {
return JWK{}, trace.BadParameter("unsupported key format %T", p)
}
// Marshal to JWK.
return JWK{
KeyType: string(defaults.ApplicationTokenKeyType),
Algorithm: string(defaults.ApplicationTokenAlgorithm),
N: base64.RawURLEncoding.EncodeToString(publicKey.N.Bytes()),
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(publicKey.E)).Bytes()),
Use: defaults.JWTUse,
KeyID: "",
}, nil
}
// UnmarshalJWK will unmarshal JWK into a crypto.PublicKey that can be used
// to validate signatures.
func UnmarshalJWK(jwk JWK) (crypto.PublicKey, error) {
if jwk.KeyType != string(defaults.ApplicationTokenKeyType) {
return nil, trace.BadParameter("unsupported key type %v", jwk.KeyType)
}
if jwk.Algorithm != string(defaults.ApplicationTokenAlgorithm) {
return nil, trace.BadParameter("unsupported algorithm %v", jwk.Algorithm)
}
n, err := base64.RawURLEncoding.DecodeString(jwk.N)
if err != nil {
return nil, trace.Wrap(err)
}
e, err := base64.RawURLEncoding.DecodeString(jwk.E)
if err != nil {
return nil, trace.Wrap(err)
}
return &rsa.PublicKey{
N: new(big.Int).SetBytes(n),
E: int(new(big.Int).SetBytes(e).Uint64()),
}, nil
}