create Idp

This commit is contained in:
kkb0318
2024-03-31 20:30:15 +09:00
parent ac571e3a97
commit d40d78ca98
8 changed files with 159 additions and 72 deletions
+5 -4
View File
@@ -5,8 +5,9 @@ go 1.21
toolchain go1.21.8
require (
github.com/aws/aws-sdk-go-v2 v1.26.0
github.com/aws/aws-sdk-go-v2 v1.26.1
github.com/aws/aws-sdk-go-v2/config v1.27.9
github.com/aws/aws-sdk-go-v2/service/iam v1.31.4
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0
github.com/go-jose/go-jose/v4 v4.0.1
github.com/onsi/ginkgo/v2 v2.17.1
@@ -21,8 +22,8 @@ require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.9 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
@@ -32,7 +33,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+10 -8
View File
@@ -1,5 +1,5 @@
github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA=
github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo=
github.com/aws/aws-sdk-go-v2/config v1.27.9 h1:gRx/NwpNEFSk+yQlgmk1bmxxvQ5TyJ76CWXs9XScTqg=
@@ -8,14 +8,16 @@ github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMN
github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 h1:af5YzcLf80tv4Em4jWVD75lpnOHSBkPUZxZfGkrI3HI=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4 h1:SIkD6T4zGQ+1YIit22wi37CGNkrE7mXV1vNA5VpI3TI=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4/go.mod h1:XfeqbsG0HNedNs0GT+ju4Bs+pFAwsrlzcRdMvdNVf5s=
github.com/aws/aws-sdk-go-v2/service/iam v1.31.4 h1:eVm30ZIDv//r6Aogat9I88b5YX1xASSLcEDqHYRPVl0=
github.com/aws/aws-sdk-go-v2/service/iam v1.31.4/go.mod h1:aXWImQV0uTW35LM0A/T4wEg6R1/ReXUu4SM6/lUHYK0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6 h1:NkHCgg0Ck86c5PTOzBZ0JRccI51suJDg5lgFtxBu1ek=
@@ -32,8 +34,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1A
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0=
github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw=
github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+35
View File
@@ -7,6 +7,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/iam"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
@@ -24,6 +25,12 @@ func NewAwsClient(ctx context.Context, region string) (*AwsConfig, error) {
return &AwsConfig{config: cfg}, nil
}
func (a *AwsConfig) IamCient() *AwsIamClient {
return &AwsIamClient{
iam.NewFromConfig(a.config),
}
}
func (a *AwsConfig) S3Cient(bucketName string) *AwsS3Client {
return &AwsS3Client{
bucketName,
@@ -51,3 +58,31 @@ func (a *AwsS3Client) CreateBucket(ctx context.Context) error {
})
return err
}
func (a *AwsS3Client) BucketName() string {
return a.bucketName
}
func (a *AwsS3Client) Region() string {
return a.client.Options().Region
}
type AwsIamClient struct {
client *iam.Client
}
func (a *AwsIamClient) CreateOIDCProvider(ctx context.Context, providerUrl string) (string, error) {
result, err := a.client.CreateOpenIDConnectProvider(ctx, &iam.CreateOpenIDConnectProviderInput{
Url: &providerUrl,
ClientIDList: []string{"sts.amazonaws.com"},
ThumbprintList: []string{},
})
if err != nil {
return "", err
}
return *result.OpenIDConnectProviderArn, nil
}
func (a *AwsIamClient) Region() string {
return a.client.Options().Region
}
+15 -6
View File
@@ -58,8 +58,9 @@ func (r *IRSASetupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
}
func (r *IRSASetupReconciler) reconcile(ctx context.Context) error {
var idp selfhosted.OIDCIdProvider
var oidcCreator selfhosted.OIDCIdPCreator
var discoveryContents selfhosted.OIDCIdPDiscoveryContents
var discovery selfhosted.OIDCIdPDiscovery
var idp selfhosted.OIDCIdP
keyPair, err := selfhosted.CreateKeyPair()
if err != nil {
return err
@@ -68,20 +69,28 @@ func (r *IRSASetupReconciler) reconcile(ctx context.Context) error {
if err != nil {
return err
}
idp = oidc.NewIdProvider(jwk, "issuerHostPath", "keys.json")
discoveryContents = oidc.NewIdPDiscoveryContents(jwk, "issuerHostPath", "keys.json")
awsConfig, err := awsclient.NewAwsClient(ctx, "ap-northeast-1")
if err != nil {
return err
}
oidcCreator, err = oidc.NewS3IdPCreator(awsConfig, "my-bucket-name")
discovery, err = oidc.NewS3IdPDiscovery(awsConfig, "my-bucket-name")
if err != nil {
return err
}
err = oidcCreator.CreateStorage()
err = discovery.CreateStorage()
if err != nil {
return err
}
err = oidcCreator.Upload(ctx, idp)
err = discovery.Upload(ctx, discoveryContents)
if err != nil {
return err
}
idp, err = oidc.NewAwsIdP(awsConfig, discovery)
if err != nil {
return err
}
_, err = idp.Create(ctx)
if err != nil {
return err
}
+11 -4
View File
@@ -2,13 +2,20 @@ package selfhosted
import "context"
type OIDCIdProvider interface {
type OIDCIdPDiscoveryContents interface {
Discovery() ([]byte, error)
JWK() ([]byte, error)
JWKsFileName() string
}
type OIDCIdPDiscovery interface {
CreateStorage() error
Upload(ctx context.Context, o OIDCIdPDiscoveryContents) error
Endpoint() string
}
type OIDCIdPCreator interface {
CreateStorage() error
Upload(ctx context.Context, o OIDCIdProvider) error
type OIDCIdP interface {
Create(ctx context.Context) (string, error)
IsUpdate() (bool, error)
Update(ctx context.Context) error
}
+16 -39
View File
@@ -1,57 +1,34 @@
package oidc
import (
"encoding/json"
"fmt"
"context"
"github.com/kkb0318/irsa-manager/internal/client"
"github.com/kkb0318/irsa-manager/internal/selfhosted"
)
type IdProvider struct {
jwk *selfhosted.JWK
issuerHostPath string
jwksFileName string
type AwsIdP struct {
iamClient *client.AwsIamClient
discovery selfhosted.OIDCIdPDiscovery
}
type OIDCDiscoveryConfiguration struct {
Issuer string `json:"issuer"`
JWKSURI string `json:"jwks_uri"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
ClaimsSupported []string `json:"claims_supported"`
func NewAwsIdP(awsConfig *client.AwsConfig, discovery selfhosted.OIDCIdPDiscovery) (*AwsIdP, error) {
iamClient := awsConfig.IamCient()
return &AwsIdP{iamClient, discovery}, nil
}
func (p *IdProvider) Discovery() ([]byte, error) {
oidcConfig := OIDCDiscoveryConfiguration{
Issuer: fmt.Sprintf("https://%s/", p.issuerHostPath),
JWKSURI: fmt.Sprintf("https://%s/%s", p.issuerHostPath, p.jwksFileName),
AuthorizationEndpoint: "urn:kubernetes:programmatic_authorization",
ResponseTypesSupported: []string{"id_token"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
ClaimsSupported: []string{"sub", "iss"},
}
jsonData, err := json.MarshalIndent(oidcConfig, "", " ")
func (a *AwsIdP) Create(ctx context.Context) (string, error) {
arn, err := a.iamClient.CreateOIDCProvider(ctx, a.discovery.Endpoint())
if err != nil {
return nil, err
return "", err
}
return jsonData, nil
return arn, nil
}
func (p *IdProvider) JWK() ([]byte, error) {
jsonData, err := json.MarshalIndent(p.jwk.GetKeys(), "", " ")
if err != nil {
return nil, err
}
return jsonData, nil
func (a *AwsIdP) Update(ctx context.Context) error {
return nil
}
func (p *IdProvider) Endpoint() string {
return ""
}
func NewIdProvider(jwk *selfhosted.JWK, issuerHostPath, jwksFileName string) *IdProvider {
return &IdProvider{jwk, issuerHostPath, jwksFileName}
func (a *AwsIdP) IsUpdate() (bool, error) {
return false, nil
}
@@ -10,19 +10,19 @@ import (
const CONFIGURATION_PATH = ".well-known/openid-configuration"
type S3IdPCreator struct {
type S3IdPDiscovery struct {
s3Client *client.AwsS3Client
}
// NewS3IdPCreator initializes a new instance of S3IdPCreator with the specified AWS region and bucket name.
// NewS3IdPDiscovery initializes a new instance of S3IdPCreator with the specified AWS region and bucket name.
// This function attempts to create an AWS client configured for the specified region.
func NewS3IdPCreator(awsConfig *client.AwsConfig, bucketName string) (*S3IdPCreator, error) {
func NewS3IdPDiscovery(awsConfig *client.AwsConfig, bucketName string) (*S3IdPDiscovery, error) {
s3Client := awsConfig.S3Cient(bucketName)
return &S3IdPCreator{s3Client}, nil
return &S3IdPDiscovery{s3Client}, nil
}
// CreateStorage creates an S3 bucket
func (s *S3IdPCreator) CreateStorage() error {
func (s *S3IdPDiscovery) CreateStorage() error {
err := s.s3Client.CreateBucket(context.TODO())
if err != nil {
return fmt.Errorf("unable to create bucket, %w", err)
@@ -32,7 +32,7 @@ func (s *S3IdPCreator) CreateStorage() error {
// Upload uploads the OIDC provider's discovery configuration and JSON Web Key Set (JWKS) to the specified AWS S3 bucket.
// This method is responsible for uploading the necessary OIDC configuration files to S3, making them accessible for OIDC clients.
func (s *S3IdPCreator) Upload(ctx context.Context, o selfhosted.OIDCIdProvider) error {
func (s *S3IdPDiscovery) Upload(ctx context.Context, o selfhosted.OIDCIdPDiscoveryContents) error {
discovery, err := o.Discovery()
if err != nil {
return nil
@@ -51,7 +51,7 @@ func (s *S3IdPCreator) Upload(ctx context.Context, o selfhosted.OIDCIdProvider)
return nil
}
err = s.s3Client.PutObject(ctx,
"keys.json",
o.JWKsFileName(),
jwk,
)
if err != nil {
@@ -60,9 +60,8 @@ func (s *S3IdPCreator) Upload(ctx context.Context, o selfhosted.OIDCIdProvider)
return nil
}
// issuerHostPath constructs the URL path for the OIDC issuer based on the provided AWS region and bucket name.
// Endpoint constructs the URL path for the OIDC issuer based on the provided AWS region and bucket name.
// This utility function generates the expected host path for accessing the OIDC configuration stored in an S3 bucket.
func issuerHostPath(region, bucketName string) string {
hostName := fmt.Sprintf("s3-%s.amazonaws.com", region)
return fmt.Sprintf("%s/%s", hostName, bucketName)
func (p *S3IdPDiscovery) Endpoint() string {
return fmt.Sprintf("s3-%s.amazonaws.com/%s", p.s3Client.Region(), p.s3Client.BucketName())
}
@@ -0,0 +1,57 @@
package oidc
import (
"encoding/json"
"fmt"
"github.com/kkb0318/irsa-manager/internal/selfhosted"
)
type IdPDiscoveryContents struct {
jwk *selfhosted.JWK
issuerHostPath string
jwksFileName string
}
type oidcDiscoveryConfiguration struct {
Issuer string `json:"issuer"`
JWKSURI string `json:"jwks_uri"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
ClaimsSupported []string `json:"claims_supported"`
}
func (p *IdPDiscoveryContents) Discovery() ([]byte, error) {
oidcConfig := oidcDiscoveryConfiguration{
Issuer: fmt.Sprintf("https://%s/", p.issuerHostPath),
JWKSURI: fmt.Sprintf("https://%s/%s", p.issuerHostPath, p.jwksFileName),
AuthorizationEndpoint: "urn:kubernetes:programmatic_authorization",
ResponseTypesSupported: []string{"id_token"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
ClaimsSupported: []string{"sub", "iss"},
}
jsonData, err := json.MarshalIndent(oidcConfig, "", " ")
if err != nil {
return nil, err
}
return jsonData, nil
}
func (p *IdPDiscoveryContents) JWK() ([]byte, error) {
jsonData, err := json.MarshalIndent(p.jwk.GetKeys(), "", " ")
if err != nil {
return nil, err
}
return jsonData, nil
}
func (p *IdPDiscoveryContents) JWKsFileName() string {
return p.jwksFileName
}
func NewIdPDiscoveryContents(jwk *selfhosted.JWK, issuerHostPath, jwksFileName string) *IdPDiscoveryContents {
return &IdPDiscoveryContents{jwk, issuerHostPath, jwksFileName}
}