Skip to content

Commit

Permalink
Merge pull request crossplane-contrib#36 from negz/evasivekubernetess…
Browse files Browse the repository at this point in the history
…ecrets

Propagate EKS connection secret updates
  • Loading branch information
negz committed Oct 17, 2019
2 parents 6e43662 + efc3bf6 commit fe6952a
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 171 deletions.
28 changes: 1 addition & 27 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,20 @@ require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 // indirect
github.com/aws/aws-sdk-go-v2 v0.5.0
github.com/beorn7/perks v1.0.1 // indirect
github.com/crossplaneio/crossplane v0.0.0-20190912232140-a5489468a5b1
github.com/crossplaneio/crossplane-runtime v0.0.0-20190930210014-19891e990a89
github.com/crossplaneio/crossplane-runtime v0.0.0-20191016194050-7384779dc024
github.com/ghodss/yaml v1.0.0
github.com/go-ini/ini v1.46.0
github.com/go-logr/zapr v0.1.1 // indirect
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d // indirect
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.3.0
github.com/google/uuid v1.1.1 // indirect
github.com/googleapis/gnostic v0.3.0 // indirect
github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/imdario/mergo v0.3.7 // indirect
github.com/json-iterator/go v1.1.7 // indirect
github.com/onsi/ginkgo v1.9.0 // indirect
github.com/onsi/gomega v1.5.0
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 // indirect
github.com/pkg/errors v0.8.1
github.com/prometheus/common v0.6.0 // indirect
github.com/prometheus/procfs v0.0.3 // indirect
github.com/spf13/pflag v1.0.3 // indirect
github.com/stretchr/objx v0.2.0 // indirect
github.com/stretchr/testify v1.3.0
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/zap v1.10.0 // indirect
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
google.golang.org/appengine v1.6.1 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/ini.v1 v1.47.0 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
k8s.io/klog v0.3.3 // indirect
k8s.io/kube-openapi v0.0.0-20190722073852-5e22f3d471e6 // indirect
k8s.io/utils v0.0.0-20190801114015-581e00157fb1 // indirect
sigs.k8s.io/controller-runtime v0.2.0
)
7 changes: 5 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ 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/crossplaneio/crossplane v0.0.0-20190912232140-a5489468a5b1 h1:ymeAN2cP5B+9YF/YGAyg8qSZvwifrTA9g2RfuSTr9qo=
github.com/crossplaneio/crossplane v0.0.0-20190912232140-a5489468a5b1/go.mod h1:xVb0QYtSLx3C19b4M04aJ4n0W34UhS/3HdOdwrWV7W8=
github.com/crossplaneio/crossplane-runtime v0.0.0-20190930210014-19891e990a89 h1:9/MD5juPXxa5I5ncCP6/CxHzpLwtwc/gkpXOf9dJAfo=
github.com/crossplaneio/crossplane-runtime v0.0.0-20190930210014-19891e990a89/go.mod h1:o7ddv/LcAmIEoQ3BCpahyeIboqof5auR+TlIZ7/eB04=
github.com/crossplaneio/crossplane-runtime v0.0.0-20191016194050-7384779dc024 h1:eeA0ErAEVK/c3R8mybfdoIh7eXRUxs8FV/+tT0LR59s=
github.com/crossplaneio/crossplane-runtime v0.0.0-20191016194050-7384779dc024/go.mod h1:FMlJ6k7pUZdxQrjh0B33D2b79iBac+xcMEHTWiruXao=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down Expand Up @@ -116,6 +116,7 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.9.0 h1:SZjF721BByVj8QH636/8S2DnX4n0Re3SteMmw3N+tzc=
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
Expand Down Expand Up @@ -221,6 +222,7 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b h1:mSUCVIwDx4hfXJfWsOPfdzEHxzb2Xjl6BQ8YgPnazQA=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gomodules.xyz/jsonpatch/v2 v2.0.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
Expand Down Expand Up @@ -263,6 +265,7 @@ k8s.io/kube-openapi v0.0.0-20190722073852-5e22f3d471e6/go.mod h1:RZvgC8MSN6DjiMV
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
sigs.k8s.io/controller-runtime v0.2.0-beta.5/go.mod h1:HweyYKQ8fBuzdu2bdaeBJvsFgAi/OqBBnrVGXcqKhME=
sigs.k8s.io/controller-runtime v0.2.0 h1:5gL30PXOisGZl+Osi4CmLhvMUj77BO3wJeouKF2va50=
sigs.k8s.io/controller-runtime v0.2.0/go.mod h1:ZHqrRDZi3f6BzONcvlUxkqCKgwasGk5FZrnSv9TVZF4=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
Expand Down
1 change: 1 addition & 0 deletions pkg/controller/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func (c *Controllers) SetupWithManager(mgr ctrl.Manager) error {
&cache.ReplicationGroupClaimController{},
&cache.ReplicationGroupController{},
&compute.EKSClusterClaimController{},
&compute.EKSClusterSecretController{},
&compute.EKSClusterController{},
&rds.PostgreSQLInstanceClaimController{},
&rds.MySQLInstanceClaimController{},
Expand Down
119 changes: 64 additions & 55 deletions pkg/controller/compute/eks.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,24 @@ import (
"encoding/base64"
"fmt"
"strings"
"time"

cf "github.com/aws/aws-sdk-go-v2/service/cloudformation"
"github.com/ghodss/yaml"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

awscomputev1alpha2 "github.com/crossplaneio/stack-aws/apis/compute/v1alpha2"
awsv1alpha2 "github.com/crossplaneio/stack-aws/apis/v1alpha2"
awsClient "github.com/crossplaneio/stack-aws/pkg/clients"
aws "github.com/crossplaneio/stack-aws/pkg/clients"
cloudformationclient "github.com/crossplaneio/stack-aws/pkg/clients/cloudformation"

runtimev1alpha1 "github.com/crossplaneio/crossplane-runtime/apis/core/v1alpha1"
Expand All @@ -49,7 +48,6 @@ import (
"github.com/crossplaneio/crossplane-runtime/pkg/logging"
"github.com/crossplaneio/crossplane-runtime/pkg/meta"
"github.com/crossplaneio/crossplane-runtime/pkg/resource"
"github.com/crossplaneio/crossplane-runtime/pkg/util"
)

const (
Expand All @@ -63,10 +61,14 @@ const (
)

var (
log = logging.Logger.WithName("controller." + controllerName)
ctx = context.Background()
result = reconcile.Result{}
resultRequeue = reconcile.Result{Requeue: true}
log = logging.Logger.WithName("controller." + controllerName)
ctx = context.Background()
)

// Amounts of time we wait before requeuing a reconcile.
const (
aShortWait = 30 * time.Second
aLongWait = 60 * time.Second
)

// CloudFormation States that are non-transitory
Expand All @@ -88,9 +90,7 @@ var (
// Reconciler reconciles a Provider object
type Reconciler struct {
client.Client
scheme *runtime.Scheme
kubeclient kubernetes.Interface
recorder record.EventRecorder
publisher resource.ManagedConnectionPublisher

connect func(*awscomputev1alpha2.EKSCluster) (eks.Client, error)
create func(*awscomputev1alpha2.EKSCluster, eks.Client) (reconcile.Result, error)
Expand All @@ -108,10 +108,8 @@ type EKSClusterController struct{}
// and Start it when the Manager is Started.
func (c *EKSClusterController) SetupWithManager(mgr ctrl.Manager) error {
r := &Reconciler{
Client: mgr.GetClient(),
scheme: mgr.GetScheme(),
kubeclient: kubernetes.NewForConfigOrDie(mgr.GetConfig()),
recorder: mgr.GetEventRecorderFor(controllerName),
Client: mgr.GetClient(),
publisher: resource.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme()),
}
r.connect = r._connect
r.create = r._create
Expand All @@ -129,26 +127,31 @@ func (c *EKSClusterController) SetupWithManager(mgr ctrl.Manager) error {
// fail - helper function to set fail condition with reason and message
func (r *Reconciler) fail(instance *awscomputev1alpha2.EKSCluster, err error) (reconcile.Result, error) {
instance.Status.SetConditions(runtimev1alpha1.ReconcileError(err))
return resultRequeue, r.Update(context.TODO(), instance)

// If this is the first time we've encountered this error we'll be requeued
// implicitly due to the status update. Otherwise we requeue after a short
// wait in case the error condition was resolved.
return reconcile.Result{RequeueAfter: aShortWait}, r.Update(ctx, instance)
}

func (r *Reconciler) _connect(instance *awscomputev1alpha2.EKSCluster) (eks.Client, error) {
// Fetch Provider
p := &awsv1alpha2.Provider{}
err := r.Get(ctx, meta.NamespacedNameOf(instance.Spec.ProviderReference), p)
if err != nil {
if err := r.Get(ctx, meta.NamespacedNameOf(instance.Spec.ProviderReference), p); err != nil {
return nil, err
}

// Get Provider's AWS Config
config, err := awsClient.Config(r.kubeclient, p)
if err != nil {
s := &v1.Secret{}
n := types.NamespacedName{Namespace: p.GetNamespace(), Name: p.Spec.Secret.Name}
if err := r.Get(ctx, n, s); err != nil {
return nil, err
}

// Connection Region must be with Spec.Region
if string(instance.Spec.Region) != config.Region {
config.Region = string(instance.Spec.Region)
// NOTE(negz): EKS clusters must specify a region for creation. They never
// use the provider's region. This should be addressed per the below issue.
// https://github.com/crossplaneio/stack-aws/issues/38
config, err := aws.LoadConfig(s.Data[p.Spec.Secret.Key], aws.DefaultSection, string(instance.Spec.Region))
if err != nil {
return nil, err
}

// Create new EKS Client
Expand All @@ -163,9 +166,12 @@ func (r *Reconciler) _create(instance *awscomputev1alpha2.EKSCluster, client eks
createdCluster, err := client.Create(clusterName, instance.Spec)
if err != nil && !eks.IsErrorAlreadyExists(err) {
if eks.IsErrorBadRequest(err) {
// do not requeue on bad requests
// If this was the first time we encountered this error we'll be
// requeued implicitly. Otherwise there's no point requeuing, since
// the error indicates our spec is bad and needs updating before
// anything will work.
instance.Status.SetConditions(runtimev1alpha1.ReconcileError(err))
return result, r.Update(ctx, instance)
return reconcile.Result{}, r.Update(ctx, instance)
}
return r.fail(instance, err)
}
Expand All @@ -179,7 +185,11 @@ func (r *Reconciler) _create(instance *awscomputev1alpha2.EKSCluster, client eks
instance.Status.ClusterName = clusterName

instance.Status.SetConditions(runtimev1alpha1.ReconcileSuccess())
return resultRequeue, r.Update(ctx, instance)

// We'll be requeued immediately the first time we update our status
// condition. Otherwise we want to requeue after a short wait in order to
// determine whether the cluster is ready.
return reconcile.Result{RequeueAfter: aShortWait}, r.Update(ctx, instance)
}

// generateAWSAuthConfigMap generates the configmap for configure auth
Expand Down Expand Up @@ -276,7 +286,9 @@ func (r *Reconciler) _sync(instance *awscomputev1alpha2.EKSCluster, client eks.C

if cluster.Status != awscomputev1alpha2.ClusterStatusActive {
instance.Status.SetConditions(runtimev1alpha1.ReconcileSuccess())
return resultRequeue, nil

// Requeue after a short wait to see if the cluster has become ready.
return reconcile.Result{RequeueAfter: aShortWait}, nil
}

// Create workers
Expand All @@ -287,7 +299,11 @@ func (r *Reconciler) _sync(instance *awscomputev1alpha2.EKSCluster, client eks.C
}
instance.Status.CloudFormationStackID = clusterWorkers.WorkerStackID
instance.Status.SetConditions(runtimev1alpha1.ReconcileSuccess())
return resultRequeue, r.Update(ctx, instance)

// We'll likely be requeued implicitly due to the status update, but
// otherwise we want to requeue a reconcile after a short wait to check
// on the worker node creation.
return reconcile.Result{RequeueAfter: aShortWait}, r.Update(ctx, instance)
}

clusterWorker, err := client.GetWorkerNodes(instance.Status.CloudFormationStackID)
Expand All @@ -301,7 +317,8 @@ func (r *Reconciler) _sync(instance *awscomputev1alpha2.EKSCluster, client eks.C

if !completedCFState[clusterWorker.WorkersStatus] {
instance.Status.SetConditions(runtimev1alpha1.ReconcileSuccess())
return resultRequeue, r.Update(ctx, instance)

return reconcile.Result{RequeueAfter: aShortWait}, r.Update(ctx, instance)
}

if err := r.awsauth(cluster, instance, client, clusterWorker.WorkerARN); err != nil {
Expand All @@ -318,7 +335,9 @@ func (r *Reconciler) _sync(instance *awscomputev1alpha2.EKSCluster, client eks.C
instance.Status.SetConditions(runtimev1alpha1.Available(), runtimev1alpha1.ReconcileSuccess())
resource.SetBindable(instance)

return result, r.Update(ctx, instance)
// Our cluster is available. Requeue speculative yafter a long wait in case
// the cluster has changed.
return reconcile.Result{RequeueAfter: aLongWait}, r.Update(ctx, instance)
}

func (r *Reconciler) _secret(cluster *eks.Cluster, instance *awscomputev1alpha2.EKSCluster, client eks.Client) error {
Expand All @@ -333,20 +352,11 @@ func (r *Reconciler) _secret(cluster *eks.Cluster, instance *awscomputev1alpha2.
return err
}

// secret := instance.ConnectionSecret()
secret := resource.ConnectionSecretFor(instance, awscomputev1alpha2.EKSClusterGroupVersionKind)
data := make(map[string][]byte)
data[runtimev1alpha1.ResourceCredentialsSecretEndpointKey] = []byte(cluster.Endpoint)
data[runtimev1alpha1.ResourceCredentialsSecretCAKey] = caData
data[runtimev1alpha1.ResourceCredentialsTokenKey] = []byte(token)
secret.Data = data

// create connection secret
if _, err := util.ApplySecret(r.kubeclient, secret); err != nil {
return err
}

return nil
return r.publisher.PublishConnection(ctx, instance, resource.ConnectionDetails{
runtimev1alpha1.ResourceCredentialsSecretEndpointKey: []byte(cluster.Endpoint),
runtimev1alpha1.ResourceCredentialsSecretCAKey: caData,
runtimev1alpha1.ResourceCredentialsTokenKey: []byte(token),
})
}

// _delete check reclaim policy and if needed delete the eks cluster resource
Expand All @@ -371,7 +381,10 @@ func (r *Reconciler) _delete(instance *awscomputev1alpha2.EKSCluster, client eks

meta.RemoveFinalizer(instance, finalizer)
instance.Status.SetConditions(runtimev1alpha1.ReconcileSuccess())
return result, r.Update(ctx, instance)

// No need to requeue a reconcile if we've successfully asked for the
// cluster to be deleted.
return reconcile.Result{Requeue: false}, r.Update(ctx, instance)
}

// Reconcile reads that state of the cluster for a Provider object and makes changes based on the state read
Expand All @@ -382,13 +395,9 @@ func (r *Reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err
instance := &awscomputev1alpha2.EKSCluster{}
err := r.Get(ctx, request.NamespacedName, instance)
if err != nil {
if kerrors.IsNotFound(err) {
// Object not found, return. Created objects are automatically garbage collected.
// For additional cleanup logic use finalizers.
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
return reconcile.Result{}, err
// No need to requeue if the resource no longer exists, otherwise we'll
// be requeued because we return an error.
return reconcile.Result{}, resource.IgnoreNotFound(err)
}

// Create EKS Client
Expand Down
Loading

0 comments on commit fe6952a

Please sign in to comment.