Skip to content

Commit

Permalink
Allow bound service account token expiry to be configurable through e…
Browse files Browse the repository at this point in the history
…nv vars

Signed-off-by: Max Cao <[email protected]>
  • Loading branch information
maxcao13 committed Dec 11, 2024
1 parent 982dd1d commit de4e9ae
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 19 deletions.
11 changes: 8 additions & 3 deletions cmd/operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ func main() {
os.Exit(1)
}

_, err = kedautil.GetBoundServiceAccountTokenExpiry()
if err != nil {
setupLog.Error(err, "invalid "+kedautil.BoundServiceAccountTokenExpiryEnvVar)
os.Exit(1)
}

globalHTTPTimeout := time.Duration(globalHTTPTimeoutMS) * time.Millisecond
eventRecorder := mgr.GetEventRecorderFor("keda-operator")

Expand All @@ -225,9 +231,8 @@ func main() {
}

authClientSet := &authentication.AuthClientSet{
TokenReviewInterface: kubeClientset.AuthenticationV1().TokenReviews(),
CoreV1Interface: kubeClientset.CoreV1(),
SecretLister: secretInformer.Lister(),
CoreV1Interface: kubeClientset.CoreV1(),
SecretLister: secretInformer.Lister(),
}

scaledHandler := scaling.NewScaleHandler(mgr.GetClient(), scaleClient, mgr.GetScheme(), globalHTTPTimeout, eventRecorder, authClientSet)
Expand Down
2 changes: 0 additions & 2 deletions pkg/scalers/authentication/authentication_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ import (
libs "github.com/dysnix/predictkube-libs/external/configs"
"github.com/dysnix/predictkube-libs/external/http_transport"
pConfig "github.com/prometheus/common/config"
authenticationv1client "k8s.io/client-go/kubernetes/typed/authentication/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
corev1listers "k8s.io/client-go/listers/core/v1"

kedautil "github.com/kedacore/keda/v2/pkg/util"
)

type AuthClientSet struct {
authenticationv1client.TokenReviewInterface
corev1client.CoreV1Interface
corev1listers.SecretLister
}
Expand Down
20 changes: 11 additions & 9 deletions pkg/scaling/resolver/scale_resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"strconv"
"strings"

"github.com/aws/smithy-go/ptr"
"github.com/go-logr/logr"
appsv1 "k8s.io/api/apps/v1"
authenticationv1 "k8s.io/api/authentication/v1"
Expand All @@ -32,6 +31,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/utils/ptr"
"knative.dev/pkg/apis/duck"
duckv1 "knative.dev/pkg/apis/duck/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -52,9 +52,10 @@ const (
)

var (
kedaNamespace, _ = util.GetClusterObjectNamespace()
restrictSecretAccess = util.GetRestrictSecretAccess()
log = logf.Log.WithName("scale_resolvers")
kedaNamespace, _ = util.GetClusterObjectNamespace()
restrictSecretAccess = util.GetRestrictSecretAccess()
boundServiceAccountTokenExpiry, _ = util.GetBoundServiceAccountTokenExpiry()
log = logf.Log.WithName("scale_resolvers")
)

// isSecretAccessRestricted returns whether secret access need to be restricted in KEDA namespace
Expand Down Expand Up @@ -620,11 +621,12 @@ func resolveBoundServiceAccountToken(ctx context.Context, client client.Client,
logger.Error(err, "error trying to get service account from namespace", "ServiceAccount.Namespace", namespace, "ServiceAccount.Name", serviceAccountName)
return ""
}
return generateToken(ctx, serviceAccountName, namespace, acs)
return generateBoundServiceAccountToken(ctx, serviceAccountName, namespace, acs)
}

func generateToken(ctx context.Context, serviceAccountName, namespace string, acs *authentication.AuthClientSet) string {
expirationSeconds := ptr.Int64(3600) // We default the token expiry to 1 hour
// generateBoundServiceAccountToken creates a Kubernetes token for a namespaced service account with a runtime-configurable expiration time and returns the token string.
func generateBoundServiceAccountToken(ctx context.Context, serviceAccountName, namespace string, acs *authentication.AuthClientSet) string {
expirationSeconds := ptr.To[int64](int64(boundServiceAccountTokenExpiry.Seconds()))
token, err := acs.CoreV1Interface.ServiceAccounts(namespace).CreateToken(
ctx,
serviceAccountName,
Expand All @@ -636,10 +638,10 @@ func generateToken(ctx context.Context, serviceAccountName, namespace string, ac
metav1.CreateOptions{},
)
if err != nil {
log.Error(err, "error trying to create token for service account", "ServiceAccount.Name", serviceAccountName)
log.V(1).Error(err, "error trying to create bound service account token for service account", "ServiceAccount.Name", serviceAccountName)
return ""
}
log.Info("Service account token created successfully", "ServiceAccount.Name", serviceAccountName)
log.V(1).Info("Bound service account token created successfully", "ServiceAccount.Name", serviceAccountName)
return token.Status.Token
}

Expand Down
7 changes: 2 additions & 5 deletions pkg/scaling/resolver/scale_resolvers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/scheme"
authenticationv1client "k8s.io/client-go/kubernetes/typed/authentication/v1"
corev1listers "k8s.io/client-go/listers/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
logf "sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -708,7 +707,6 @@ func TestResolveAuthRef(t *testing.T) {
}
ctrl := gomock.NewController(t)
var secretsLister corev1listers.SecretLister
var tokenReviewInterface authenticationv1client.TokenReviewInterface
mockCoreV1Interface := mock_serviceaccounts.NewMockCoreV1Interface(ctrl)
mockServiceAccountInterface := mockCoreV1Interface.GetServiceAccountInterface()
tokenRequest := &authv1.TokenRequest{
Expand All @@ -731,9 +729,8 @@ func TestResolveAuthRef(t *testing.T) {
test.podSpec,
namespace,
&authentication.AuthClientSet{
SecretLister: secretsLister,
CoreV1Interface: mockCoreV1Interface,
TokenReviewInterface: tokenReviewInterface,
SecretLister: secretsLister,
CoreV1Interface: mockCoreV1Interface,
},
)

Expand Down
21 changes: 21 additions & 0 deletions pkg/util/env_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ limitations under the License.
package util

import (
"fmt"
"os"
"strconv"
"time"

"k8s.io/utils/ptr"
)

const RestrictSecretAccessEnvVar = "KEDA_RESTRICT_SECRET_ACCESS"
const BoundServiceAccountTokenExpiryEnvVar = "KEDA_BOUND_SERVICE_ACCOUNT_TOKEN_EXPIRY"

var clusterObjectNamespaceCache *string

Expand Down Expand Up @@ -90,3 +94,20 @@ func GetPodNamespace() string {
func GetRestrictSecretAccess() string {
return os.Getenv(RestrictSecretAccessEnvVar)
}

// GetBoundServiceAccountTokenExpiry retrieves the value of the environment variable of KEDA_BOUND_SERVICE_ACCOUNT_TOKEN_EXPIRY
func GetBoundServiceAccountTokenExpiry() (*time.Duration, error) {
expiry, err := ResolveOsEnvDuration(BoundServiceAccountTokenExpiryEnvVar)
if err != nil {
return nil, err
}
if expiry == nil {
return ptr.To[time.Duration](time.Hour), nil // if blank, default to 1 hour

}
if *expiry < time.Hour || *expiry > 6*time.Hour {
return nil, fmt.Errorf("invalid value for %s: %s, must be between 1h and 6h", BoundServiceAccountTokenExpiryEnvVar, expiry.String()) // Must be between 1 hour and 6 hours

}
return expiry, nil
}

0 comments on commit de4e9ae

Please sign in to comment.