Skip to content

Commit

Permalink
Update all provider config
Browse files Browse the repository at this point in the history
Signed-off-by: SK Ali Arman <[email protected]>
  • Loading branch information
sheikh-arman committed Nov 24, 2023
1 parent a36fe72 commit 075c722
Show file tree
Hide file tree
Showing 5 changed files with 687 additions and 155 deletions.
113 changes: 81 additions & 32 deletions apis/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ Copyright 2022 Upbound Inc.
package v1beta1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// A ProviderConfigSpec defines the desired state of a ProviderConfig.
Expand All @@ -18,7 +17,74 @@ type ProviderConfigSpec struct {
// AssumeRoleChain defines the options for assuming an IAM role
AssumeRoleChain []AssumeRoleOptions `json:"assumeRoleChain,omitempty"`

// Endpoint is where you can override the default endpoint configuration
// of AWS calls made by the provider.
// +optional
Endpoint *EndpointConfig `json:"endpoint,omitempty"`
// Whether to skip credentials validation via the STS API.
// This can be useful for testing and for AWS API implementations that do not have STS available.
// +optional
SkipCredsValidation bool `json:"skip_credentials_validation,omitempty"`
// Whether to skip validation of provided region name.
// Useful for AWS-like implementations that use their own region names or to bypass the validation for
// regions that aren't publicly available yet.
// +optional
SkipRegionValidation bool `json:"skip_region_validation,omitempty"`
// Whether to enable the request to use path-style addressing, i.e., https://s3.amazonaws.com/BUCKET/KEY.
// +optional
S3UsePathStyle bool `json:"s3_use_path_style,omitempty"`
// Whether to skip the AWS Metadata API check
// Useful for AWS API implementations that do not have a metadata API endpoint.
// +optional
SkipMetadataApiCheck bool `json:"skip_metadata_api_check,omitempty"`
// Whether to skip requesting the account ID.
// Useful for AWS API implementations that do not have the IAM, STS API, or metadata API
// +optional
SkipReqAccountId bool `json:"skip_requesting_account_id,omitempty"`
}

// AssumeRoleOptions define the options for assuming an IAM Role
// Fields are similar to the STS AssumeRoleOptions in the AWS SDK
type AssumeRoleOptions struct {
// AssumeRoleARN to assume with provider credentials
RoleARN *string `json:"roleARN,omitempty"`

// ExternalID is the external ID used when assuming role.
// +optional
ExternalID *string `json:"externalID,omitempty"`

// Tags is list of session tags that you want to pass. Each session tag consists of a key
// name and an associated value. For more information about session tags, see
// Tagging STS Sessions
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html).
// +optional
Tags []Tag `json:"tags,omitempty"`

// TransitiveTagKeys is a list of keys for session tags that you want to set as transitive. If you set a
// tag key as transitive, the corresponding key and value passes to subsequent
// sessions in a role chain. For more information, see Chaining Roles with Session Tags
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining).
// +optional
TransitiveTagKeys []string `json:"transitiveTagKeys,omitempty"`
}

// AssumeRoleWithWebIdentityOptions define the options for assuming an IAM Role
// Fields are similar to the STS WebIdentityRoleOptions in the AWS SDK
type AssumeRoleWithWebIdentityOptions struct {
// AssumeRoleARN to assume with provider credentials
RoleARN *string `json:"roleARN,omitempty"`

// RoleSessionName is the session name, if you wish to uniquely identify this session.
// +optional
RoleSessionName string `json:"roleSessionName,omitempty"`
}

// Upbound defines the options for authenticating using Upbound as an identity
// provider.
type Upbound struct {
// WebIdentity defines the options for assuming an IAM role with a Web
// Identity.
WebIdentity *AssumeRoleWithWebIdentityOptions `json:"webIdentity,omitempty"`
}

// EndpointConfig is used to configure the AWS client for a custom endpoint.
Expand Down Expand Up @@ -122,31 +188,6 @@ type DynamicURLConfig struct {
Host string `json:"host"`
}

// AssumeRoleOptions define the options for assuming an IAM Role
// Fields are similar to the STS AssumeRoleOptions in the AWS SDK
type AssumeRoleOptions struct {
// AssumeRoleARN to assume with provider credentials
RoleARN *string `json:"roleARN,omitempty"`

// ExternalID is the external ID used when assuming role.
// +optional
ExternalID *string `json:"externalID,omitempty"`

// Tags is list of session tags that you want to pass. Each session tag consists of a key
// name and an associated value. For more information about session tags, see
// Tagging STS Sessions
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html).
// +optional
Tags []Tag `json:"tags,omitempty"`

// TransitiveTagKeys is a list of keys for session tags that you want to set as transitive. If you set a
// tag key as transitive, the corresponding key and value passes to subsequent
// sessions in a role chain. For more information, see Chaining Roles with Session Tags
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining).
// +optional
TransitiveTagKeys []string `json:"transitiveTagKeys,omitempty"`
}

// Tag is session tag that can be used to assume an IAM Role
type Tag struct {
// Name of the tag.
Expand All @@ -161,9 +202,15 @@ type Tag struct {
// ProviderCredentials required to authenticate.
type ProviderCredentials struct {
// Source of the provider credentials.
// +kubebuilder:validation:Enum=None;Secret;InjectedIdentity;Environment;Filesystem
// +kubebuilder:validation:Enum=None;Secret;IRSA;WebIdentity;Upbound
Source xpv1.CredentialsSource `json:"source"`

// WebIdentity defines the options for assuming an IAM role with a Web Identity.
WebIdentity *AssumeRoleWithWebIdentityOptions `json:"webIdentity,omitempty"`

// Upbound defines the options for authenticating using Upbound as an identity provider.
Upbound *Upbound `json:"upbound,omitempty"`

xpv1.CommonCredentialSelectors `json:",inline"`
}

Expand All @@ -174,12 +221,13 @@ type ProviderConfigStatus struct {

// +kubebuilder:object:root=true

// A ProviderConfig configures a Aws provider.
// A ProviderConfig configures the AWS provider.
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1
// +kubebuilder:printcolumn:name="SOURCE",type="string",JSONPath=".spec.source",priority=1
// +kubebuilder:resource:scope=Cluster
// +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,aws}
// +kubebuilder:resource:scope=Cluster,categories={crossplane,providerconfig,aws}
// +kubebuilder:storageversion
type ProviderConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand All @@ -204,7 +252,8 @@ type ProviderConfigList struct {
// +kubebuilder:printcolumn:name="CONFIG-NAME",type="string",JSONPath=".providerConfigRef.name"
// +kubebuilder:printcolumn:name="RESOURCE-KIND",type="string",JSONPath=".resourceRef.kind"
// +kubebuilder:printcolumn:name="RESOURCE-NAME",type="string",JSONPath=".resourceRef.name"
// +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,aws}
// +kubebuilder:resource:scope=Cluster,categories={crossplane,providerconfig,aws}
// +kubebuilder:storageversion
type ProviderConfigUsage struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
78 changes: 55 additions & 23 deletions cmd/provider/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main

import (
"context"
"github.com/crossplane/crossplane-runtime/pkg/certificates"
"github.com/crossplane/crossplane-runtime/pkg/feature"
"gopkg.in/alecthomas/kingpin.v2"
"os"
Expand Down Expand Up @@ -36,21 +37,24 @@ import (

func main() {
var (
app = kingpin.New(filepath.Base(os.Args[0]), "Terraform based Crossplane provider for Aws").DefaultEnvars()
app = kingpin.New(filepath.Base(os.Args[0]), "AWS support for Crossplane.").DefaultEnvars()
debug = app.Flag("debug", "Run with debug logging.").Short('d').Bool()
syncPeriod = app.Flag("sync", "Controller manager sync period such as 300ms, 1.5h, or 2h45m").Short('s').Default("1h").Duration()
syncInterval = app.Flag("sync", "Sync interval controls how often all resources will be double checked for drift.").Short('s').Default("1h").Duration()
pollInterval = app.Flag("poll", "Poll interval controls how often an individual resource should be checked for drift.").Default("10m").Duration()
leaderElection = app.Flag("leader-election", "Use leader election for the controller manager.").Short('l').Default("false").OverrideDefaultFromEnvar("LEADER_ELECTION").Bool()
maxReconcileRate = app.Flag("max-reconcile-rate", "The global maximum rate per second at which resources may be checked for drift from the desired state.").Default("10").Int()

terraformVersion = app.Flag("terraform-version", "Terraform version.").Required().Envar("TERRAFORM_VERSION").String()
providerSource = app.Flag("terraform-provider-source", "Terraform provider source.").Required().Envar("TERRAFORM_PROVIDER_SOURCE").String()
providerVersion = app.Flag("terraform-provider-version", "Terraform provider version.").Required().Envar("TERRAFORM_PROVIDER_VERSION").String()
maxReconcileRate = app.Flag("max-reconcile-rate", "The global maximum rate per second at which resources may be checked for drift from the desired state.").Default("100").Int()
pluginProcessTTL = app.Flag("provider-ttl", "TTL for the native plugin processes before they are replaced. Changing the default may increase memory consumption.").Default("100").Int()

namespace = app.Flag("namespace", "Namespace used to set as default scope in default secret store config.").Default("crossplane-system").Envar("POD_NAMESPACE").String()
enableExternalSecretStores = app.Flag("enable-external-secret-stores", "Enable support for ExternalSecretStores.").Default("false").Envar("ENABLE_EXTERNAL_SECRET_STORES").Bool()
essTLSCertsPath = app.Flag("ess-tls-cert-dir", "Path of ESS TLS certificates.").Envar("ESS_TLS_CERTS_DIR").String()
enableManagementPolicies = app.Flag("enable-management-policies", "Enable support for Management Policies.").Default("true").Envar("ENABLE_MANAGEMENT_POLICIES").Bool()
)
setupConfig := &clients.SetupConfig{}
setupConfig.TerraformVersion = app.Flag("terraform-version", "Terraform version.").Required().Envar("TERRAFORM_VERSION").String()
setupConfig.NativeProviderSource = app.Flag("terraform-provider-source", "Terraform provider source.").Required().Envar("TERRAFORM_PROVIDER_SOURCE").String()
setupConfig.NativeProviderVersion = app.Flag("terraform-provider-version", "Terraform provider version.").Required().Envar("TERRAFORM_PROVIDER_VERSION").String()
setupConfig.NativeProviderPath = app.Flag("terraform-native-provider-path", "Terraform native provider path for shared execution.").Default("").Envar("TERRAFORM_NATIVE_PROVIDER_PATH").String()

kingpin.MustParse(app.Parse(os.Args[1:]))

Expand All @@ -63,27 +67,43 @@ func main() {
ctrl.SetLogger(zl)
}

log.Debug("Starting", "sync-period", syncPeriod.String(), "poll-interval", pollInterval.String(), "max-reconcile-rate", *maxReconcileRate)
// currently, we configure the jitter to be the 5% of the poll interval
pollJitter := time.Duration(float64(*pollInterval) * 0.05)
log.Debug("Starting", "sync-interval", syncInterval.String(),
"poll-interval", pollInterval.String(), "poll-jitter", pollJitter, "max-reconcile-rate", *maxReconcileRate)

cfg, err := ctrl.GetConfig()
kingpin.FatalIfError(err, "Cannot get API server rest config")

mgr, err := ctrl.NewManager(cfg, ctrl.Options{
mgr, err := ctrl.NewManager(ratelimiter.LimitRESTConfig(cfg, *maxReconcileRate), ctrl.Options{
LeaderElection: *leaderElection,
LeaderElectionID: "crossplane-leader-election-provider-aws",
LeaderElectionID: "crossplane-leader-election-provider-aws-accessanalyzer",
Cache: cache.Options{
SyncPeriod: syncPeriod,
SyncPeriod: syncInterval,
},
LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
LeaseDuration: func() *time.Duration { d := 60 * time.Second; return &d }(),
RenewDeadline: func() *time.Duration { d := 50 * time.Second; return &d }(),
})
kingpin.FatalIfError(err, "Cannot create controller manager")
kingpin.FatalIfError(apis.AddToScheme(mgr.GetScheme()), "Cannot add Aws APIs to scheme")
kingpin.FatalIfError(apis.AddToScheme(mgr.GetScheme()), "Cannot add AWS APIs to scheme")

// if the native Terraform provider plugin's path is not configured via
// the env. variable TERRAFORM_NATIVE_PROVIDER_PATH or
// the `--terraform-native-provider-path` command-line option,
// we do not use the shared gRPC server and default to the regular
// Terraform CLI behaviour (of forking a plugin process per invocation).
// This removes some complexity for setting up development environments.
setupConfig.DefaultScheduler = terraform.NewNoOpProviderScheduler()
if len(*setupConfig.NativeProviderPath) != 0 {
setupConfig.DefaultScheduler = terraform.NewSharedProviderScheduler(log, *pluginProcessTTL,
terraform.WithSharedProviderOptions(terraform.WithNativeProviderPath(*setupConfig.NativeProviderPath), terraform.WithNativeProviderName("registry.terraform.io/"+*setupConfig.NativeProviderSource)))
}

ctx := context.Background()
provider, err := config.GetProvider(ctx, false)
kingpin.FatalIfError(err, "Cannot initialize the provider configuration")
setupConfig.TerraformProvider = provider.TerraformProvider
o := tjcontroller.Options{
Options: xpcontroller.Options{
Logger: log,
Expand All @@ -92,19 +112,35 @@ func main() {
MaxConcurrentReconciles: *maxReconcileRate,
Features: &feature.Flags{},
},
Provider: provider,
// use the following WorkspaceStoreOption to enable the shared gRPC mode
// terraform.WithProviderRunner(terraform.NewSharedProvider(log, os.Getenv("TERRAFORM_NATIVE_PROVIDER_PATH"), terraform.WithNativeProviderArgs("-debuggable")))
WorkspaceStore: terraform.NewWorkspaceStore(log),
SetupFn: clients.TerraformSetupBuilder(*terraformVersion, *providerSource, *providerVersion, provider.TerraformProvider),
Provider: provider,
SetupFn: clients.SelectTerraformSetup(log, setupConfig),
PollJitter: pollJitter,
OperationTrackerStore: tjcontroller.NewOperationStore(log),
}

if *enableManagementPolicies {
o.Features.Enable(features.EnableBetaManagementPolicies)
log.Info("Beta feature enabled", "flag", features.EnableBetaManagementPolicies)
}

o.WorkspaceStore = terraform.NewWorkspaceStore(log, terraform.WithDisableInit(len(*setupConfig.NativeProviderPath) != 0), terraform.WithProcessReportInterval(*pollInterval), terraform.WithFeatures(o.Features))

if *enableExternalSecretStores {
o.SecretStoreConfigGVK = &v1alpha1.StoreConfigGroupVersionKind
log.Info("Alpha feature enabled", "flag", features.EnableAlphaExternalSecretStores)

o.ESSOptions = &tjcontroller.ESSOptions{}
if *essTLSCertsPath != "" {
log.Info("ESS TLS certificates path is set. Loading mTLS configuration.")
tCfg, err := certificates.LoadMTLSConfig(filepath.Join(*essTLSCertsPath, "ca.crt"), filepath.Join(*essTLSCertsPath, "tls.crt"), filepath.Join(*essTLSCertsPath, "tls.key"), false)
kingpin.FatalIfError(err, "Cannot load ESS TLS config.")

o.ESSOptions.TLSConfig = tCfg
}

// Ensure default store config exists.
kingpin.FatalIfError(resource.Ignore(kerrors.IsAlreadyExists, mgr.GetClient().Create(context.Background(), &v1alpha1.StoreConfig{
kingpin.FatalIfError(resource.Ignore(kerrors.IsAlreadyExists, mgr.GetClient().Create(ctx, &v1alpha1.StoreConfig{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
Expand All @@ -115,14 +151,10 @@ func main() {
DefaultScope: *namespace,
},
},
Status: v1alpha1.StoreConfigStatus{},
})), "cannot create default store config")
}

if *enableManagementPolicies {
o.Features.Enable(features.EnableBetaManagementPolicies)
log.Info("Beta feature enabled", "flag", features.EnableBetaManagementPolicies)
}

kingpin.FatalIfError(controller.Setup(mgr, o), "Cannot setup Aws controllers")
kingpin.FatalIfError(mgr.Start(ctrl.SetupSignalHandler()), "Cannot start controller manager")
}
Loading

0 comments on commit 075c722

Please sign in to comment.