Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

operator: Add OpenShift CloudCredentials support for AWS STS #11524

Merged
merged 64 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
db9df8d
operator: adds AWS sts support
JoaoBraveCoding Dec 13, 2023
cb00a76
Refactored switch case
JoaoBraveCoding Dec 14, 2023
25cd135
Add mounting of SA
JoaoBraveCoding Dec 14, 2023
8d50ef5
make fmt
JoaoBraveCoding Dec 14, 2023
ce45467
SA Token mount path updated acording with instalation
JoaoBraveCoding Dec 15, 2023
b1e4bf0
Added test case for configure_test.go
JoaoBraveCoding Dec 15, 2023
2a2330f
Added missing tests and moved logic to determine sa token path to
JoaoBraveCoding Dec 18, 2023
155b976
Update CHANGELOG.md
JoaoBraveCoding Dec 18, 2023
ba306cf
Merge branch 'main' into log-4544
JoaoBraveCoding Dec 18, 2023
e2a2085
Address review comments
JoaoBraveCoding Dec 19, 2023
42831ac
Merge branch 'main' into log-4544
JoaoBraveCoding Dec 19, 2023
7505b00
Refactored extract secret
JoaoBraveCoding Dec 19, 2023
d4b7092
Merge branch 'main' into log-4544
JoaoBraveCoding Dec 21, 2023
e2707ad
Moved SetSAToken to be called outside the package
JoaoBraveCoding Dec 21, 2023
9024459
Moved openshiftEnabled inside Options
JoaoBraveCoding Dec 22, 2023
966fba1
Set default audience
JoaoBraveCoding Dec 22, 2023
82099eb
Fix tests
JoaoBraveCoding Dec 22, 2023
66db2a5
Move SetSATokenPath outside of manifests package
JoaoBraveCoding Jan 5, 2024
0fe5373
operator: Adds CCO support to openshift AWS STS use-case
JoaoBraveCoding Dec 19, 2023
76686da
Use CCO secret by setting AWS_SHARED_CREDENTIALS_FILE
JoaoBraveCoding Jan 5, 2024
df33309
Merge remote-tracking branch 'upstream/main' into operator-aws-cco-su…
periklis Jan 11, 2024
9e29609
Rebuild bundles
periklis Jan 11, 2024
69f16ab
Fix regression on last merge from upstream/main
periklis Jan 11, 2024
574aad2
Fix controller loop watching instead of owning CredentialsRequest
periklis Jan 11, 2024
c66110f
Refactor storage options from handler into internal package
periklis Jan 11, 2024
2623046
Merge remote-tracking branch 'upstream/main' into operator-aws-cco-su…
periklis Jan 11, 2024
c85bba0
fix tests
periklis Jan 11, 2024
326e240
Revert "fix tests"
periklis Jan 12, 2024
0264258
Revert "Refactor storage options from handler into internal package"
periklis Jan 12, 2024
5566fcd
Fix tests
periklis Jan 12, 2024
cb6be89
Fix linter
periklis Jan 12, 2024
6b52ffe
Merge remote-tracking branch 'upstream/main' into operator-aws-cco-su…
periklis Jan 13, 2024
41ea6f7
Refactor code base to non-manifest code to handlers
periklis Jan 13, 2024
2bffba0
Add test for degraded error when cloud credentials secret missing
periklis Jan 13, 2024
845043e
Add restart annotation for cloud credetials SHA1 changes
periklis Jan 13, 2024
9222e4d
Add changelog entry
periklis Jan 14, 2024
1cbb58d
Add missing tests
periklis Jan 14, 2024
0617963
Fix typo
periklis Jan 14, 2024
b9e86ab
Refactor CredentialsRequest reconciliation
periklis Jan 15, 2024
bc41c4d
Add credentialsrequest reconciliation tests
periklis Jan 16, 2024
4b8ba24
Fix reconciliation for managed auth environment
periklis Jan 16, 2024
f8fa63b
Fix docs
periklis Jan 16, 2024
ac30b91
Remove obsolete error case
periklis Jan 16, 2024
5a7deca
Update operator/internal/handlers/internal/storage/secrets.go
periklis Jan 16, 2024
636c92a
Merge remote-tracking branch 'upstream/main' into operator-aws-cco-su…
periklis Jan 16, 2024
ecfb768
Merge remote-tracking branch 'upstream/main' into operator-aws-cco-su…
periklis Jan 18, 2024
fc244c1
Merge remote-tracking branch 'upstream/main' into operator-aws-cco-su…
periklis Jan 23, 2024
6f37231
Update openshift/cloud-credential-operator module to release-4.15
periklis Jan 23, 2024
df58d43
Add support to deploy lokistack objstore secret using STS auth
periklis Jan 23, 2024
6dca698
Remove obsolet echo statements
periklis Jan 23, 2024
c50bcb8
Apply suggestions from code review
periklis Jan 24, 2024
a0229ef
Apply suggestions from code review
periklis Jan 24, 2024
f8c81e7
Refactor term usage for isManagedAuth
periklis Jan 24, 2024
470bfa1
Add missing function
periklis Jan 24, 2024
3693c99
Apply code review suggestions
periklis Jan 24, 2024
c786627
Merge branch 'main' into log-4701
periklis Jan 24, 2024
0ea9727
Merge branch 'main' into log-4701
periklis Jan 25, 2024
2012d7f
Merge branch 'main' into log-4701
periklis Jan 25, 2024
6d0b8d4
Merge branch 'main' into log-4701
periklis Jan 25, 2024
2e76a7e
Merge branch 'main' into log-4701
periklis Jan 25, 2024
e458c6b
Fix shellcheck
periklis Jan 25, 2024
d92eb12
Merge branch 'main' into log-4701
periklis Jan 25, 2024
7487823
Merge branch 'main' into log-4701
periklis Jan 26, 2024
fa10cde
Merge branch 'main' into log-4701
periklis Jan 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions operator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Main

- [11524](https://github.com/grafana/loki/pull/11524) **JoaoBraveCoding**, **periklis**: Add OpenShift cloud credentials support for AWS STS
- [11513](https://github.com/grafana/loki/pull/11513) **btaani**: Add a custom metric that collects Lokistacks requiring a schema upgrade
- [11718](https://github.com/grafana/loki/pull/11718) **periklis**: Upgrade k8s.io, sigs.k8s.io and openshift deps
- [11671](https://github.com/grafana/loki/pull/11671) **JoaoBraveCoding**: Update mixins to fix structured metadata dashboards
Expand Down
7 changes: 7 additions & 0 deletions operator/apis/config/v1/projectconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ type OpenShiftFeatureGates struct {

// Dashboards enables the loki-mixin dashboards into the OpenShift Console
Dashboards bool `json:"dashboards,omitempty"`

// ManagedAuthEnv enabled when the operator installation is on OpenShift STS clusters.
ManagedAuthEnv bool
}

func (o OpenShiftFeatureGates) ManagedAuthEnabled() bool {
return o.Enabled && o.ManagedAuthEnv
}

// FeatureGates is the supported set of all operator feature gates.
Expand Down
6 changes: 6 additions & 0 deletions operator/apis/loki/v1/lokistack_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,12 @@ const (
ReasonMissingObjectStorageSecret LokiStackConditionReason = "MissingObjectStorageSecret"
// ReasonInvalidObjectStorageSecret when the format of the secret is invalid.
ReasonInvalidObjectStorageSecret LokiStackConditionReason = "InvalidObjectStorageSecret"
// ReasonMissingCredentialsRequest when the required request for managed auth credentials to object
// storage is missing.
ReasonMissingCredentialsRequest LokiStackConditionReason = "MissingCredentialsRequest"
// ReasonMissingManagedAuthSecret when the required secret for managed auth credentials to object
// storage is missing.
ReasonMissingManagedAuthSecret LokiStackConditionReason = "MissingManagedAuthenticationSecret"
// ReasonInvalidObjectStorageSchema when the spec contains an invalid schema(s).
ReasonInvalidObjectStorageSchema LokiStackConditionReason = "InvalidObjectStorageSchema"
// ReasonMissingObjectStorageCAConfigMap when the required configmap to verify object storage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,14 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: docker.io/grafana/loki-operator:0.5.0
createdAt: "2024-01-19T14:20:59Z"
createdAt: "2024-01-23T12:26:52Z"
description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components.
features.operators.openshift.io/disconnected: "true"
features.operators.openshift.io/fips-compliant: "false"
features.operators.openshift.io/proxy-aware: "true"
features.operators.openshift.io/tls-profiles: "true"
features.operators.openshift.io/token-auth-aws: "false"
features.operators.openshift.io/token-auth-aws: "true"
features.operators.openshift.io/token-auth-azure: "false"
features.operators.openshift.io/token-auth-gcp: "false"
operators.operatorframework.io/builder: operator-sdk-unknown
Expand Down Expand Up @@ -1463,6 +1463,16 @@ spec:
- patch
- update
- watch
- apiGroups:
- cloudcredential.openshift.io
resources:
- credentialsrequests
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: docker.io/grafana/loki-operator:0.5.0
createdAt: "2024-01-19T14:20:57Z"
createdAt: "2024-01-23T12:26:50Z"
description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components.
operators.operatorframework.io/builder: operator-sdk-unknown
Expand Down Expand Up @@ -1443,6 +1443,16 @@ spec:
- patch
- update
- watch
- apiGroups:
- cloudcredential.openshift.io
resources:
- credentialsrequests
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: quay.io/openshift-logging/loki-operator:0.1.0
createdAt: "2024-01-19T14:21:01Z"
createdAt: "2024-01-23T12:26:54Z"
description: |
The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging.
## Prerequisites and Requirements
Expand All @@ -164,7 +164,7 @@ metadata:
features.operators.openshift.io/fips-compliant: "false"
features.operators.openshift.io/proxy-aware: "true"
features.operators.openshift.io/tls-profiles: "true"
features.operators.openshift.io/token-auth-aws: "false"
features.operators.openshift.io/token-auth-aws: "true"
features.operators.openshift.io/token-auth-azure: "false"
features.operators.openshift.io/token-auth-gcp: "false"
olm.skipRange: '>=5.7.0-0 <5.9.0'
Expand Down Expand Up @@ -1448,6 +1448,16 @@ spec:
- patch
- update
- watch
- apiGroups:
- cloudcredential.openshift.io
resources:
- credentialsrequests
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ metadata:
features.operators.openshift.io/fips-compliant: "false"
features.operators.openshift.io/proxy-aware: "true"
features.operators.openshift.io/tls-profiles: "true"
features.operators.openshift.io/token-auth-aws: "false"
features.operators.openshift.io/token-auth-aws: "true"
features.operators.openshift.io/token-auth-azure: "false"
features.operators.openshift.io/token-auth-gcp: "false"
repository: https://github.com/grafana/loki/tree/main/operator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ metadata:
features.operators.openshift.io/fips-compliant: "false"
features.operators.openshift.io/proxy-aware: "true"
features.operators.openshift.io/tls-profiles: "true"
features.operators.openshift.io/token-auth-aws: "false"
features.operators.openshift.io/token-auth-aws: "true"
features.operators.openshift.io/token-auth-azure: "false"
features.operators.openshift.io/token-auth-gcp: "false"
olm.skipRange: '>=5.7.0-0 <5.9.0'
Expand Down
10 changes: 10 additions & 0 deletions operator/config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ rules:
- patch
- update
- watch
- apiGroups:
- cloudcredential.openshift.io
resources:
- credentialsrequests
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
71 changes: 71 additions & 0 deletions operator/controllers/loki/credentialsrequests_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package controllers

import (
"context"

"github.com/go-logr/logr"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/grafana/loki/operator/controllers/loki/internal/lokistack"
"github.com/grafana/loki/operator/controllers/loki/internal/management/state"
"github.com/grafana/loki/operator/internal/external/k8s"
"github.com/grafana/loki/operator/internal/handlers"
)

// CredentialsRequestsReconciler reconciles a single CredentialsRequest resource for each LokiStack request.
type CredentialsRequestsReconciler struct {
client.Client
Scheme *runtime.Scheme
Log logr.Logger
}

// Reconcile creates a single CredentialsRequest per LokiStack for the OpenShift cloud-credentials-operator (CCO) to
// provide a managed cloud credentials Secret. On successful creation, the LokiStack resource is annotated
// with `loki.grafana.com/credentials-request-secret-ref` that refers to the secret provided by CCO. If the LokiStack
// resource is not found its accompanying CredentialsRequest resource is deleted.
func (r *CredentialsRequestsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var stack lokiv1.LokiStack
if err := r.Client.Get(ctx, req.NamespacedName, &stack); err != nil {
if apierrors.IsNotFound(err) {
return ctrl.Result{}, handlers.DeleteCredentialsRequest(ctx, r.Client, req.NamespacedName)
}
return ctrl.Result{}, err
}

managed, err := state.IsManaged(ctx, req, r.Client)
if err != nil {
return ctrl.Result{}, err
}
if !managed {
r.Log.Info("Skipping reconciliation for unmanaged LokiStack resource", "name", req.String())
// Stop requeueing for unmanaged LokiStack custom resources
return ctrl.Result{}, nil
}

secretRef, err := handlers.CreateCredentialsRequest(ctx, r.Client, req.NamespacedName)
if err != nil {
return ctrl.Result{}, err
}

if err := lokistack.AnnotateForCredentialsRequest(ctx, r.Client, req.NamespacedName, secretRef); err != nil {
return ctrl.Result{}, err
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *CredentialsRequestsReconciler) SetupWithManager(mgr ctrl.Manager) error {
b := ctrl.NewControllerManagedBy(mgr)
return r.buildController(k8s.NewCtrlBuilder(b))
}

func (r *CredentialsRequestsReconciler) buildController(bld k8s.Builder) error {
return bld.
For(&lokiv1.LokiStack{}).
Complete(r)
}
155 changes: 155 additions & 0 deletions operator/controllers/loki/credentialsrequests_controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package controllers

import (
"context"
"testing"

cloudcredentialsv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1"
"github.com/stretchr/testify/require"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/grafana/loki/operator/internal/external/k8s/k8sfakes"
"github.com/grafana/loki/operator/internal/manifests/storage"
)

func TestCredentialsRequestController_RegistersCustomResource_WithDefaultPredicates(t *testing.T) {
b := &k8sfakes.FakeBuilder{}
k := &k8sfakes.FakeClient{}
c := &CredentialsRequestsReconciler{Client: k, Scheme: scheme}

b.ForReturns(b)
b.OwnsReturns(b)

err := c.buildController(b)
require.NoError(t, err)

// Require only one For-Call for the custom resource
require.Equal(t, 1, b.ForCallCount())

// Require For-call with LokiStack resource
obj, _ := b.ForArgsForCall(0)
require.Equal(t, &lokiv1.LokiStack{}, obj)
}

func TestCredentialsRequestController_DeleteCredentialsRequest_WhenLokiStackNotFound(t *testing.T) {
k := &k8sfakes.FakeClient{}
c := &CredentialsRequestsReconciler{Client: k, Scheme: scheme}
r := ctrl.Request{
NamespacedName: types.NamespacedName{
Name: "my-stack",
Namespace: "ns",
},
}

// Set managed auth environment
t.Setenv("ROLEARN", "a-role-arn")

k.GetStub = func(_ context.Context, key types.NamespacedName, _ client.Object, _ ...client.GetOption) error {
if key.Name == r.Name && key.Namespace == r.Namespace {
return apierrors.NewNotFound(schema.GroupResource{}, "lokistack not found")
}
return nil
}

res, err := c.Reconcile(context.Background(), r)
require.NoError(t, err)
require.Equal(t, ctrl.Result{}, res)
require.Equal(t, 1, k.DeleteCallCount())
}

func TestCredentialsRequestController_CreateCredentialsRequest_WhenLokiStackNotAnnotated(t *testing.T) {
k := &k8sfakes.FakeClient{}
c := &CredentialsRequestsReconciler{Client: k, Scheme: scheme}
r := ctrl.Request{
NamespacedName: types.NamespacedName{
Name: "my-stack",
Namespace: "ns",
},
}
s := lokiv1.LokiStack{
ObjectMeta: metav1.ObjectMeta{
Name: "my-stack",
Namespace: "ns",
},
Spec: lokiv1.LokiStackSpec{
ManagementState: lokiv1.ManagementStateManaged,
},
}

// Set managed auth environment
t.Setenv("ROLEARN", "a-role-arn")

k.GetStub = func(_ context.Context, key types.NamespacedName, out client.Object, _ ...client.GetOption) error {
if key.Name == r.Name && key.Namespace == r.Namespace {
k.SetClientObject(out, &s)
return nil
}
return apierrors.NewNotFound(schema.GroupResource{}, "lokistack not found")
}

k.CreateStub = func(_ context.Context, o client.Object, _ ...client.CreateOption) error {
_, isCredReq := o.(*cloudcredentialsv1.CredentialsRequest)
if !isCredReq {
return apierrors.NewBadRequest("something went wrong creating a credentials request")
}
return nil
}

k.UpdateStub = func(_ context.Context, o client.Object, _ ...client.UpdateOption) error {
stack, ok := o.(*lokiv1.LokiStack)
if !ok {
return apierrors.NewBadRequest("something went wrong creating a credentials request")
}

_, hasSecretRef := stack.Annotations[storage.AnnotationCredentialsRequestsSecretRef]
if !hasSecretRef {
return apierrors.NewBadRequest("something went updating the lokistack annotations")
}
return nil
}

res, err := c.Reconcile(context.Background(), r)
require.NoError(t, err)
require.Equal(t, ctrl.Result{}, res)
require.Equal(t, 1, k.CreateCallCount())
require.Equal(t, 1, k.UpdateCallCount())
}

func TestCredentialsRequestController_SkipsUnmanaged(t *testing.T) {
k := &k8sfakes.FakeClient{}
c := &CredentialsRequestsReconciler{Client: k, Scheme: scheme}
r := ctrl.Request{
NamespacedName: types.NamespacedName{
Name: "my-stack",
Namespace: "ns",
},
}

s := lokiv1.LokiStack{
ObjectMeta: metav1.ObjectMeta{
Name: "my-stack",
Namespace: "ns",
},
Spec: lokiv1.LokiStackSpec{
ManagementState: lokiv1.ManagementStateUnmanaged,
},
}

k.GetStub = func(_ context.Context, key types.NamespacedName, out client.Object, _ ...client.GetOption) error {
if key.Name == s.Name && key.Namespace == s.Namespace {
k.SetClientObject(out, &s)
return nil
}
return apierrors.NewNotFound(schema.GroupResource{}, "something not found")
}

res, err := c.Reconcile(context.Background(), r)
require.NoError(t, err)
require.Equal(t, ctrl.Result{}, res)
}
Loading
Loading