feat(operator): Change attribute value used for CCO-based credential mode (#12165)

pull/12182/head
Joao Marcal 2 years ago committed by GitHub
parent a0fce39169
commit 3eee541b1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      operator/CHANGELOG.md
  2. 4
      operator/apis/config/v1/projectconfig_types.go
  3. 22
      operator/apis/loki/v1/lokistack_types.go
  4. 2
      operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml
  5. 4
      operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml
  6. 2
      operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml
  7. 4
      operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml
  8. 2
      operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml
  9. 4
      operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml
  10. 4
      operator/config/crd/bases/loki.grafana.com_lokistacks.yaml
  11. 4
      operator/controllers/loki/lokistack_controller.go
  12. 27
      operator/docs/operator/api.md
  13. 4
      operator/docs/operator/feature-gates.md
  14. 2
      operator/hack/deploy-aws-storage-secret.sh
  15. 8
      operator/internal/config/managed_auth.go
  16. 10
      operator/internal/config/options.go
  17. 6
      operator/internal/handlers/credentialsrequest.go
  18. 20
      operator/internal/handlers/credentialsrequest_test.go
  19. 40
      operator/internal/handlers/internal/storage/secrets.go
  20. 52
      operator/internal/handlers/internal/storage/secrets_test.go
  21. 12
      operator/internal/handlers/internal/storage/storage.go
  22. 12
      operator/internal/handlers/internal/storage/storage_test.go
  23. 4
      operator/internal/manifests/openshift/credentialsrequest.go
  24. 8
      operator/internal/manifests/openshift/credentialsrequest_test.go
  25. 2
      operator/internal/manifests/openshift/options.go
  26. 32
      operator/internal/manifests/storage/configure.go
  27. 22
      operator/internal/manifests/storage/configure_test.go
  28. 2
      operator/internal/manifests/storage/options.go
  29. 4
      operator/internal/manifests/storage/var.go
  30. 6
      operator/internal/manifests/var.go
  31. 8
      operator/main.go

@ -1,5 +1,6 @@
## Main ## Main
- [12165](https://github.com/grafana/loki/pull/12165) **JoaoBraveCoding**: Change attribute value used for CCO-based credential mode
- [12157](https://github.com/grafana/loki/pull/12157) **periklis**: Fix managed auth features annotation for community-openshift bundle - [12157](https://github.com/grafana/loki/pull/12157) **periklis**: Fix managed auth features annotation for community-openshift bundle
- [12104](https://github.com/grafana/loki/pull/12104) **periklis**: Upgrade build and runtime dependencies - [12104](https://github.com/grafana/loki/pull/12104) **periklis**: Upgrade build and runtime dependencies
- [11928](https://github.com/grafana/loki/pull/11928) **periklis**: Fix remote write client timeout config rename - [11928](https://github.com/grafana/loki/pull/11928) **periklis**: Fix remote write client timeout config rename

@ -52,9 +52,9 @@ type OpenShiftFeatureGates struct {
// Dashboards enables the loki-mixin dashboards into the OpenShift Console // Dashboards enables the loki-mixin dashboards into the OpenShift Console
Dashboards bool `json:"dashboards,omitempty"` Dashboards bool `json:"dashboards,omitempty"`
// ManagedAuthEnv is true when OpenShift-functions are enabled and the operator has detected // TokenCCOAuthEnv is true when OpenShift-functions are enabled and the operator has detected
// that it is running with some kind of "workload identity" (AWS STS, Azure WIF) enabled. // that it is running with some kind of "workload identity" (AWS STS, Azure WIF) enabled.
ManagedAuthEnv bool TokenCCOAuthEnv bool
} }
// FeatureGates is the supported set of all operator feature gates. // FeatureGates is the supported set of all operator feature gates.

@ -1070,12 +1070,10 @@ const (
ReasonMissingObjectStorageSecret LokiStackConditionReason = "MissingObjectStorageSecret" ReasonMissingObjectStorageSecret LokiStackConditionReason = "MissingObjectStorageSecret"
// ReasonInvalidObjectStorageSecret when the format of the secret is invalid. // ReasonInvalidObjectStorageSecret when the format of the secret is invalid.
ReasonInvalidObjectStorageSecret LokiStackConditionReason = "InvalidObjectStorageSecret" ReasonInvalidObjectStorageSecret LokiStackConditionReason = "InvalidObjectStorageSecret"
// ReasonMissingCredentialsRequest when the required request for managed auth credentials to object // ReasonMissingTokenCCOAuthSecret when the secret generated by CCO for token authentication is missing.
// storage is missing. // This is usually a transient error because the secret is not immediately available after creating the
ReasonMissingCredentialsRequest LokiStackConditionReason = "MissingCredentialsRequest" // CredentialsRequest, but it can persist if the CCO or its configuration are incorrect.
// ReasonMissingManagedAuthSecret when the required secret for managed auth credentials to object ReasonMissingTokenCCOAuthSecret LokiStackConditionReason = "MissingTokenCCOAuthenticationSecret"
// storage is missing.
ReasonMissingManagedAuthSecret LokiStackConditionReason = "MissingManagedAuthenticationSecret"
// ReasonInvalidObjectStorageSchema when the spec contains an invalid schema(s). // ReasonInvalidObjectStorageSchema when the spec contains an invalid schema(s).
ReasonInvalidObjectStorageSchema LokiStackConditionReason = "InvalidObjectStorageSchema" ReasonInvalidObjectStorageSchema LokiStackConditionReason = "InvalidObjectStorageSchema"
// ReasonMissingObjectStorageCAConfigMap when the required configmap to verify object storage // ReasonMissingObjectStorageCAConfigMap when the required configmap to verify object storage
@ -1204,7 +1202,7 @@ type LokiStackComponentStatus struct {
// CredentialMode represents the type of authentication used for accessing the object storage. // CredentialMode represents the type of authentication used for accessing the object storage.
// //
// +kubebuilder:validation:Enum=static;token;managed // +kubebuilder:validation:Enum=static;token;token-cco
type CredentialMode string type CredentialMode string
const ( const (
@ -1216,11 +1214,11 @@ const (
// Instead, they are generated during runtime using a service, which allows for shorter-lived credentials and // Instead, they are generated during runtime using a service, which allows for shorter-lived credentials and
// much more granular control. This authentication mode is not supported for all object storage types. // much more granular control. This authentication mode is not supported for all object storage types.
CredentialModeToken CredentialMode = "token" CredentialModeToken CredentialMode = "token"
// CredentialModeManaged represents the usage of short-lived tokens retrieved from a credential source. // CredentialModeTokenCCO represents the usage of short-lived tokens retrieved from a credential source.
// This mode is similar to CredentialModeToken,but instead of having a user-configured credential source, // This mode is similar to CredentialModeToken, but instead of having a user-configured credential source,
// it is configured by the environment, for example the Cloud Credential Operator in OpenShift. // it is configured by the environment and the operator relies on the Cloud Credential Operator to provide
// This mode is only supported for certain object storage types in certain runtime environments. // a secret. This mode is only supported for certain object storage types in certain runtime environments.
CredentialModeManaged CredentialMode = "managed" CredentialModeTokenCCO CredentialMode = "token-cco"
) )
// LokiStackStorageStatus defines the observed state of // LokiStackStorageStatus defines the observed state of

@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing categories: OpenShift Optional, Logging & Tracing
certified: "false" certified: "false"
containerImage: docker.io/grafana/loki-operator:0.5.0 containerImage: docker.io/grafana/loki-operator:0.5.0
createdAt: "2024-03-11T16:01:17Z" createdAt: "2024-03-12T09:52:37Z"
description: The Community Loki Operator provides Kubernetes native deployment description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components. and management of Loki and related logging components.
features.operators.openshift.io/disconnected: "true" features.operators.openshift.io/disconnected: "true"

@ -635,7 +635,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
name: name:
description: Name of a secret in the namespace configured description: Name of a secret in the namespace configured
@ -3819,7 +3819,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
schemas: schemas:
description: |- description: |-

@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing categories: OpenShift Optional, Logging & Tracing
certified: "false" certified: "false"
containerImage: docker.io/grafana/loki-operator:0.5.0 containerImage: docker.io/grafana/loki-operator:0.5.0
createdAt: "2024-03-11T16:01:16Z" createdAt: "2024-03-12T09:52:36Z"
description: The Community Loki Operator provides Kubernetes native deployment description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components. and management of Loki and related logging components.
operators.operatorframework.io/builder: operator-sdk-unknown operators.operatorframework.io/builder: operator-sdk-unknown

@ -635,7 +635,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
name: name:
description: Name of a secret in the namespace configured description: Name of a secret in the namespace configured
@ -3819,7 +3819,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
schemas: schemas:
description: |- description: |-

@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing categories: OpenShift Optional, Logging & Tracing
certified: "false" certified: "false"
containerImage: quay.io/openshift-logging/loki-operator:0.1.0 containerImage: quay.io/openshift-logging/loki-operator:0.1.0
createdAt: "2024-03-11T16:01:19Z" createdAt: "2024-03-12T09:52:39Z"
description: | description: |
The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging. The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging.
## Prerequisites and Requirements ## Prerequisites and Requirements

@ -635,7 +635,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
name: name:
description: Name of a secret in the namespace configured description: Name of a secret in the namespace configured
@ -3819,7 +3819,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
schemas: schemas:
description: |- description: |-

@ -617,7 +617,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
name: name:
description: Name of a secret in the namespace configured description: Name of a secret in the namespace configured
@ -3801,7 +3801,7 @@ spec:
enum: enum:
- static - static
- token - token
- managed - token-cco
type: string type: string
schemas: schemas:
description: |- description: |-

@ -110,7 +110,7 @@ type LokiStackReconciler struct {
Log logr.Logger Log logr.Logger
Scheme *runtime.Scheme Scheme *runtime.Scheme
FeatureGates configv1.FeatureGates FeatureGates configv1.FeatureGates
AuthConfig *config.ManagedAuthConfig AuthConfig *config.TokenCCOAuthConfig
} }
// +kubebuilder:rbac:groups=loki.grafana.com,resources=lokistacks,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=loki.grafana.com,resources=lokistacks,verbs=get;list;watch;create;update;patch;delete
@ -179,7 +179,7 @@ func (r *LokiStackReconciler) updateResources(ctx context.Context, req ctrl.Requ
} }
} }
if r.FeatureGates.OpenShift.ManagedAuthEnv { if r.FeatureGates.OpenShift.TokenCCOAuthEnv {
if err := handlers.CreateUpdateDeleteCredentialsRequest(ctx, r.Log, r.Scheme, r.AuthConfig, r.Client, req); err != nil { if err := handlers.CreateUpdateDeleteCredentialsRequest(ctx, r.Log, r.Scheme, r.AuthConfig, r.Client, req); err != nil {
return "", err return "", err
} }

@ -1115,13 +1115,7 @@ string
<th>Description</th> <th>Description</th>
</tr> </tr>
</thead> </thead>
<tbody><tr><td><p>&#34;managed&#34;</p></td> <tbody><tr><td><p>&#34;static&#34;</p></td>
<td><p>CredentialModeManaged represents the usage of short-lived tokens retrieved from a credential source.
This mode is similar to CredentialModeToken,but instead of having a user-configured credential source,
it is configured by the environment, for example the Cloud Credential Operator in OpenShift.
This mode is only supported for certain object storage types in certain runtime environments.</p>
</td>
</tr><tr><td><p>&#34;static&#34;</p></td>
<td><p>CredentialModeStatic represents the usage of static, long-lived credentials stored in a Secret. <td><p>CredentialModeStatic represents the usage of static, long-lived credentials stored in a Secret.
This is the default authentication mode and available for all supported object storage types.</p> This is the default authentication mode and available for all supported object storage types.</p>
</td> </td>
@ -1131,6 +1125,12 @@ In this mode the static configuration does not contain credentials needed for th
Instead, they are generated during runtime using a service, which allows for shorter-lived credentials and Instead, they are generated during runtime using a service, which allows for shorter-lived credentials and
much more granular control. This authentication mode is not supported for all object storage types.</p> much more granular control. This authentication mode is not supported for all object storage types.</p>
</td> </td>
</tr><tr><td><p>&#34;token-cco&#34;</p></td>
<td><p>CredentialModeTokenCCO represents the usage of short-lived tokens retrieved from a credential source.
This mode is similar to CredentialModeToken, but instead of having a user-configured credential source,
it is configured by the environment and the operator relies on the Cloud Credential Operator to provide
a secret. This mode is only supported for certain object storage types in certain runtime environments.</p>
</td>
</tr></tbody> </tr></tbody>
</table> </table>
@ -1779,10 +1779,6 @@ with the select cluster size.</p>
</tr><tr><td><p>&#34;InvalidTenantsConfiguration&#34;</p></td> </tr><tr><td><p>&#34;InvalidTenantsConfiguration&#34;</p></td>
<td><p>ReasonInvalidTenantsConfiguration when the tenant configuration provided is invalid.</p> <td><p>ReasonInvalidTenantsConfiguration when the tenant configuration provided is invalid.</p>
</td> </td>
</tr><tr><td><p>&#34;MissingCredentialsRequest&#34;</p></td>
<td><p>ReasonMissingCredentialsRequest when the required request for managed auth credentials to object
storage is missing.</p>
</td>
</tr><tr><td><p>&#34;MissingGatewayTenantAuthenticationConfig&#34;</p></td> </tr><tr><td><p>&#34;MissingGatewayTenantAuthenticationConfig&#34;</p></td>
<td><p>ReasonMissingGatewayAuthenticationConfig when the config for when a tenant is missing authentication config</p> <td><p>ReasonMissingGatewayAuthenticationConfig when the config for when a tenant is missing authentication config</p>
</td> </td>
@ -1797,10 +1793,6 @@ for authentication is missing.</p>
<td><p>ReasonMissingGatewayTenantSecret when the required tenant secret <td><p>ReasonMissingGatewayTenantSecret when the required tenant secret
for authentication is missing.</p> for authentication is missing.</p>
</td> </td>
</tr><tr><td><p>&#34;MissingManagedAuthenticationSecret&#34;</p></td>
<td><p>ReasonMissingManagedAuthSecret when the required secret for managed auth credentials to object
storage is missing.</p>
</td>
</tr><tr><td><p>&#34;MissingObjectStorageCAConfigMap&#34;</p></td> </tr><tr><td><p>&#34;MissingObjectStorageCAConfigMap&#34;</p></td>
<td><p>ReasonMissingObjectStorageCAConfigMap when the required configmap to verify object storage <td><p>ReasonMissingObjectStorageCAConfigMap when the required configmap to verify object storage
certificates is missing.</p> certificates is missing.</p>
@ -1813,6 +1805,11 @@ storage is missing.</p>
<td><p>ReasonMissingRulerSecret when the required secret to authorization remote write connections <td><p>ReasonMissingRulerSecret when the required secret to authorization remote write connections
for the ruler is missing.</p> for the ruler is missing.</p>
</td> </td>
</tr><tr><td><p>&#34;MissingTokenCCOAuthenticationSecret&#34;</p></td>
<td><p>ReasonMissingTokenCCOAuthSecret when the secret generated by CCO for token authentication is missing.
This is usually a transient error because the secret is not immediately available after creating the
CredentialsRequest, but it can persist if the CCO or its configuration are incorrect.</p>
</td>
</tr><tr><td><p>&#34;PendingComponents&#34;</p></td> </tr><tr><td><p>&#34;PendingComponents&#34;</p></td>
<td><p>ReasonPendingComponents when all/some LokiStack components pending dependencies</p> <td><p>ReasonPendingComponents when all/some LokiStack components pending dependencies</p>
</td> </td>

@ -411,13 +411,13 @@ bool
</tr> </tr>
<tr> <tr>
<td> <td>
<code>ManagedAuthEnv</code><br/> <code>TokenCCOAuthEnv</code><br/>
<em> <em>
bool bool
</em> </em>
</td> </td>
<td> <td>
<p>ManagedAuthEnv is true when OpenShift-functions are enabled and the operator has detected <p>TokenCCOAuthEnv is true when OpenShift-functions are enabled and the operator has detected
that it is running with some kind of &ldquo;workload identity&rdquo; (AWS STS, Azure WIF) enabled.</p> that it is running with some kind of &ldquo;workload identity&rdquo; (AWS STS, Azure WIF) enabled.</p>
</td> </td>
</tr> </tr>

@ -37,7 +37,7 @@ readonly access_key_id
secret_access_key=${SECRET_ACCESS_KEY:-$(aws configure get aws_secret_access_key)} secret_access_key=${SECRET_ACCESS_KEY:-$(aws configure get aws_secret_access_key)}
readonly secret_access_key readonly secret_access_key
# Managed authentication with/without a manually provisioned AWS Role. # token authentication with/without a manually provisioned AWS Role.
readonly sts=${STS:-false} readonly sts=${STS:-false}
readonly role_arn=${2-} readonly role_arn=${2-}

@ -13,12 +13,12 @@ type AzureEnvironment struct {
Region string Region string
} }
type ManagedAuthConfig struct { type TokenCCOAuthConfig struct {
AWS *AWSEnvironment AWS *AWSEnvironment
Azure *AzureEnvironment Azure *AzureEnvironment
} }
func discoverManagedAuthConfig() *ManagedAuthConfig { func discoverTokenCCOAuthConfig() *TokenCCOAuthConfig {
// AWS // AWS
roleARN := os.Getenv("ROLEARN") roleARN := os.Getenv("ROLEARN")
@ -30,13 +30,13 @@ func discoverManagedAuthConfig() *ManagedAuthConfig {
switch { switch {
case roleARN != "": case roleARN != "":
return &ManagedAuthConfig{ return &TokenCCOAuthConfig{
AWS: &AWSEnvironment{ AWS: &AWSEnvironment{
RoleARN: roleARN, RoleARN: roleARN,
}, },
} }
case clientID != "" && tenantID != "" && subscriptionID != "": case clientID != "" && tenantID != "" && subscriptionID != "":
return &ManagedAuthConfig{ return &TokenCCOAuthConfig{
Azure: &AzureEnvironment{ Azure: &AzureEnvironment{
ClientID: clientID, ClientID: clientID,
SubscriptionID: subscriptionID, SubscriptionID: subscriptionID,

@ -17,7 +17,7 @@ import (
// LoadConfig initializes the controller configuration, optionally overriding the defaults // LoadConfig initializes the controller configuration, optionally overriding the defaults
// from a provided configuration file. // from a provided configuration file.
func LoadConfig(scheme *runtime.Scheme, configFile string) (*configv1.ProjectConfig, *ManagedAuthConfig, ctrl.Options, error) { func LoadConfig(scheme *runtime.Scheme, configFile string) (*configv1.ProjectConfig, *TokenCCOAuthConfig, ctrl.Options, error) {
options := ctrl.Options{Scheme: scheme} options := ctrl.Options{Scheme: scheme}
if configFile == "" { if configFile == "" {
return &configv1.ProjectConfig{}, nil, options, nil return &configv1.ProjectConfig{}, nil, options, nil
@ -28,13 +28,13 @@ func LoadConfig(scheme *runtime.Scheme, configFile string) (*configv1.ProjectCon
return nil, nil, options, fmt.Errorf("failed to parse controller manager config file: %w", err) return nil, nil, options, fmt.Errorf("failed to parse controller manager config file: %w", err)
} }
managedAuth := discoverManagedAuthConfig() tokenCCOAuth := discoverTokenCCOAuthConfig()
if ctrlCfg.Gates.OpenShift.Enabled && managedAuth != nil { if ctrlCfg.Gates.OpenShift.Enabled && tokenCCOAuth != nil {
ctrlCfg.Gates.OpenShift.ManagedAuthEnv = true ctrlCfg.Gates.OpenShift.TokenCCOAuthEnv = true
} }
options = mergeOptionsFromFile(options, ctrlCfg) options = mergeOptionsFromFile(options, ctrlCfg)
return ctrlCfg, managedAuth, options, nil return ctrlCfg, tokenCCOAuth, options, nil
} }
func mergeOptionsFromFile(o manager.Options, cfg *configv1.ProjectConfig) manager.Options { func mergeOptionsFromFile(o manager.Options, cfg *configv1.ProjectConfig) manager.Options {

@ -22,7 +22,7 @@ import (
// CreateUpdateDeleteCredentialsRequest creates a new CredentialsRequest resource for a Lokistack // CreateUpdateDeleteCredentialsRequest creates a new CredentialsRequest resource for a Lokistack
// to request a cloud credentials Secret resource from the OpenShift cloud-credentials-operator. // to request a cloud credentials Secret resource from the OpenShift cloud-credentials-operator.
func CreateUpdateDeleteCredentialsRequest(ctx context.Context, log logr.Logger, scheme *runtime.Scheme, managedAuth *config.ManagedAuthConfig, k k8s.Client, req ctrl.Request) error { func CreateUpdateDeleteCredentialsRequest(ctx context.Context, log logr.Logger, scheme *runtime.Scheme, tokenCCOAuth *config.TokenCCOAuthConfig, k k8s.Client, req ctrl.Request) error {
ll := log.WithValues("lokistack", req.NamespacedName, "event", "createCredentialsRequest") ll := log.WithValues("lokistack", req.NamespacedName, "event", "createCredentialsRequest")
var stack lokiv1.LokiStack var stack lokiv1.LokiStack
@ -59,7 +59,7 @@ func CreateUpdateDeleteCredentialsRequest(ctx context.Context, log logr.Logger,
LokiStackNamespace: stack.Namespace, LokiStackNamespace: stack.Namespace,
RulerName: manifests.RulerName(stack.Name), RulerName: manifests.RulerName(stack.Name),
}, },
ManagedAuth: managedAuth, TokenCCOAuth: tokenCCOAuth,
} }
credReq, err := openshift.BuildCredentialsRequest(opts) credReq, err := openshift.BuildCredentialsRequest(opts)
@ -99,7 +99,7 @@ func hasManagedCredentialMode(stack *lokiv1.LokiStack) bool {
switch stack.Spec.Storage.Secret.CredentialMode { switch stack.Spec.Storage.Secret.CredentialMode {
case lokiv1.CredentialModeStatic, lokiv1.CredentialModeToken: case lokiv1.CredentialModeStatic, lokiv1.CredentialModeToken:
return false return false
case lokiv1.CredentialModeManaged: case lokiv1.CredentialModeTokenCCO:
return true return true
default: default:
} }

@ -57,13 +57,13 @@ func TestCreateUpdateDeleteCredentialsRequest_CreateNewResource(t *testing.T) {
NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"}, NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"},
} }
managedAuth := &config.ManagedAuthConfig{ tokenCCOAuth := &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "a-role-arn", RoleARN: "a-role-arn",
}, },
} }
err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, managedAuth, k, req) err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, tokenCCOAuth, k, req)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, k.CreateCallCount()) require.Equal(t, 1, k.CreateCallCount())
@ -89,7 +89,7 @@ func TestCreateUpdateDeleteCredentialsRequest_CreateNewResourceAzure(t *testing.
NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"}, NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"},
} }
managedAuth := &config.ManagedAuthConfig{ tokenCCOAuth := &config.TokenCCOAuthConfig{
Azure: &config.AzureEnvironment{ Azure: &config.AzureEnvironment{
ClientID: "test-client-id", ClientID: "test-client-id",
SubscriptionID: "test-tenant-id", SubscriptionID: "test-tenant-id",
@ -98,7 +98,7 @@ func TestCreateUpdateDeleteCredentialsRequest_CreateNewResourceAzure(t *testing.
}, },
} }
err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, managedAuth, k, req) err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, tokenCCOAuth, k, req)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, k.CreateCallCount()) require.Equal(t, 1, k.CreateCallCount())
@ -117,7 +117,7 @@ func TestCreateUpdateDeleteCredentialsRequest_Update_WhenCredentialsRequestExist
NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"}, NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"},
} }
managedAuth := &config.ManagedAuthConfig{ tokenCCOAuth := &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "a-role-arn", RoleARN: "a-role-arn",
}, },
@ -138,7 +138,7 @@ func TestCreateUpdateDeleteCredentialsRequest_Update_WhenCredentialsRequestExist
k := credentialsRequestFakeClient(cr, lokistack) k := credentialsRequestFakeClient(cr, lokistack)
err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, managedAuth, k, req) err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, tokenCCOAuth, k, req)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 2, k.GetCallCount()) require.Equal(t, 2, k.GetCallCount())
require.Equal(t, 0, k.CreateCallCount()) require.Equal(t, 0, k.CreateCallCount())
@ -150,7 +150,7 @@ func TestCreateUpdateDeleteCredentialsRequest_DeleteExisting_WhenNotManagedMode(
NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"}, NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"},
} }
managedAuth := &config.ManagedAuthConfig{ tokenCCOAuth := &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "a-role-arn", RoleARN: "a-role-arn",
}, },
@ -178,7 +178,7 @@ func TestCreateUpdateDeleteCredentialsRequest_DeleteExisting_WhenNotManagedMode(
k := credentialsRequestFakeClient(cr, lokistack) k := credentialsRequestFakeClient(cr, lokistack)
err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, managedAuth, k, req) err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, tokenCCOAuth, k, req)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 2, k.GetCallCount()) require.Equal(t, 2, k.GetCallCount())
require.Equal(t, 0, k.CreateCallCount()) require.Equal(t, 0, k.CreateCallCount())
@ -191,7 +191,7 @@ func TestCreateUpdateDeleteCredentialsRequest_DoNothing_WhenNotManagedMode(t *te
NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"}, NamespacedName: client.ObjectKey{Name: "my-stack", Namespace: "ns"},
} }
managedAuth := &config.ManagedAuthConfig{ tokenCCOAuth := &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "a-role-arn", RoleARN: "a-role-arn",
}, },
@ -213,7 +213,7 @@ func TestCreateUpdateDeleteCredentialsRequest_DoNothing_WhenNotManagedMode(t *te
k := credentialsRequestFakeClient(nil, lokistack) k := credentialsRequestFakeClient(nil, lokistack)
err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, managedAuth, k, req) err := CreateUpdateDeleteCredentialsRequest(context.Background(), logger, scheme, tokenCCOAuth, k, req)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 2, k.GetCallCount()) require.Equal(t, 2, k.GetCallCount())
require.Equal(t, 0, k.CreateCallCount()) require.Equal(t, 0, k.CreateCallCount())

@ -53,8 +53,8 @@ const gcpAccountTypeExternal = "external_account"
func getSecrets(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg configv1.FeatureGates) (*corev1.Secret, *corev1.Secret, error) { func getSecrets(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg configv1.FeatureGates) (*corev1.Secret, *corev1.Secret, error) {
var ( var (
storageSecret corev1.Secret storageSecret corev1.Secret
managedAuthSecret corev1.Secret tokenCCOAuthSecret corev1.Secret
) )
key := client.ObjectKey{Name: stack.Spec.Storage.Secret.Name, Namespace: stack.Namespace} key := client.ObjectKey{Name: stack.Spec.Storage.Secret.Name, Namespace: stack.Namespace}
@ -69,27 +69,27 @@ func getSecrets(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg c
return nil, nil, fmt.Errorf("failed to lookup lokistack storage secret: %w", err) return nil, nil, fmt.Errorf("failed to lookup lokistack storage secret: %w", err)
} }
if fg.OpenShift.ManagedAuthEnv { if fg.OpenShift.TokenCCOAuthEnv {
secretName := storage.ManagedCredentialsSecretName(stack.Name) secretName := storage.ManagedCredentialsSecretName(stack.Name)
managedAuthCredsKey := client.ObjectKey{Name: secretName, Namespace: stack.Namespace} tokenCCOAuthCredsKey := client.ObjectKey{Name: secretName, Namespace: stack.Namespace}
if err := k.Get(ctx, managedAuthCredsKey, &managedAuthSecret); err != nil { if err := k.Get(ctx, tokenCCOAuthCredsKey, &tokenCCOAuthSecret); err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
// We don't know if this is an error yet, need to wait for evaluation of CredentialMode // We don't know if this is an error yet, need to wait for evaluation of CredentialMode
// For now we go with empty "managed secret", the eventual DegradedError will be returned later. // For now we go with empty "managed secret", the eventual DegradedError will be returned later.
return &storageSecret, nil, nil return &storageSecret, nil, nil
} }
return nil, nil, fmt.Errorf("failed to lookup OpenShift CCO managed authentication credentials secret: %w", err) return nil, nil, fmt.Errorf("failed to lookup OpenShift CCO token authentication credentials secret: %w", err)
} }
return &storageSecret, &managedAuthSecret, nil return &storageSecret, &tokenCCOAuthSecret, nil
} }
return &storageSecret, nil, nil return &storageSecret, nil, nil
} }
// extractSecrets reads the k8s obj storage secret into a manifest object storage struct if valid. // extractSecrets reads the k8s obj storage secret into a manifest object storage struct if valid.
// The managed auth is also read into the manifest object under the right circumstances. // The token cco auth is also read into the manifest object under the right circumstances.
func extractSecrets(secretSpec lokiv1.ObjectStorageSecretSpec, objStore, managedAuth *corev1.Secret, fg configv1.FeatureGates) (storage.Options, error) { func extractSecrets(secretSpec lokiv1.ObjectStorageSecretSpec, objStore, tokenCCOAuth *corev1.Secret, fg configv1.FeatureGates) (storage.Options, error) {
hash, err := hashSecretData(objStore) hash, err := hashSecretData(objStore)
if err != nil { if err != nil {
return storage.Options{}, errSecretHashError return storage.Options{}, errSecretHashError
@ -98,16 +98,16 @@ func extractSecrets(secretSpec lokiv1.ObjectStorageSecretSpec, objStore, managed
openShiftOpts := storage.OpenShiftOptions{ openShiftOpts := storage.OpenShiftOptions{
Enabled: fg.OpenShift.Enabled, Enabled: fg.OpenShift.Enabled,
} }
if managedAuth != nil { if tokenCCOAuth != nil {
var managedAuthHash string var tokenCCOAuthHash string
managedAuthHash, err = hashSecretData(managedAuth) tokenCCOAuthHash, err = hashSecretData(tokenCCOAuth)
if err != nil { if err != nil {
return storage.Options{}, errSecretHashError return storage.Options{}, errSecretHashError
} }
openShiftOpts.CloudCredentials = storage.CloudCredentials{ openShiftOpts.CloudCredentials = storage.CloudCredentials{
SecretName: managedAuth.Name, SecretName: tokenCCOAuth.Name,
SHA1: managedAuthHash, SHA1: tokenCCOAuthHash,
} }
} }
@ -161,9 +161,9 @@ func determineCredentialMode(spec lokiv1.ObjectStorageSecretSpec, secret *corev1
return spec.CredentialMode, nil return spec.CredentialMode, nil
} }
if fg.OpenShift.ManagedAuthEnv { if fg.OpenShift.TokenCCOAuthEnv {
// Default to managed credential mode on a managed-auth installation // Default to token cco credential mode on a token-cco-auth installation
return lokiv1.CredentialModeManaged, nil return lokiv1.CredentialModeTokenCCO, nil
} }
switch spec.Type { switch spec.Type {
@ -298,7 +298,7 @@ func validateAzureCredentials(s *corev1.Secret, credentialMode lokiv1.Credential
} }
return true, nil return true, nil
case lokiv1.CredentialModeManaged: case lokiv1.CredentialModeTokenCCO:
if len(accountKey) > 0 || len(clientID) > 0 || len(tenantID) > 0 || len(subscriptionID) > 0 { if len(accountKey) > 0 || len(clientID) > 0 || len(tenantID) > 0 || len(subscriptionID) > 0 {
return false, errAzureManagedIdentityNoOverride return false, errAzureManagedIdentityNoOverride
} }
@ -370,7 +370,7 @@ func extractGCSConfigSecret(s *corev1.Secret, credentialMode lokiv1.CredentialMo
WorkloadIdentity: true, WorkloadIdentity: true,
Audience: audience, Audience: audience,
}, nil }, nil
case lokiv1.CredentialModeManaged: case lokiv1.CredentialModeTokenCCO:
return nil, fmt.Errorf("%w: type: %s credentialMode: %s", errSecretUnsupportedCredentialMode, lokiv1.ObjectStorageSecretGCS, credentialMode) return nil, fmt.Errorf("%w: type: %s credentialMode: %s", errSecretUnsupportedCredentialMode, lokiv1.ObjectStorageSecretGCS, credentialMode)
default: default:
} }
@ -409,7 +409,7 @@ func extractS3ConfigSecret(s *corev1.Secret, credentialMode lokiv1.CredentialMod
} }
switch credentialMode { switch credentialMode {
case lokiv1.CredentialModeManaged: case lokiv1.CredentialModeTokenCCO:
cfg.STS = true cfg.STS = true
cfg.Audience = string(audience) cfg.Audience = string(audience)
// Do not allow users overriding the role arn provided on Loki Operator installation // Do not allow users overriding the role arn provided on Loki Operator installation

@ -143,7 +143,7 @@ func TestAzureExtract(t *testing.T) {
wantError: "missing secret field: subscription_id", wantError: "missing secret field: subscription_id",
}, },
{ {
name: "managed auth - no auth override", name: "token cco auth - no auth override",
secret: &corev1.Secret{ secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "test"}, ObjectMeta: metav1.ObjectMeta{Name: "test"},
Data: map[string][]byte{ Data: map[string][]byte{
@ -159,8 +159,8 @@ func TestAzureExtract(t *testing.T) {
}, },
featureGates: configv1.FeatureGates{ featureGates: configv1.FeatureGates{
OpenShift: configv1.OpenShiftFeatureGates{ OpenShift: configv1.OpenShiftFeatureGates{
Enabled: true, Enabled: true,
ManagedAuthEnv: true, TokenCCOAuthEnv: true,
}, },
}, },
wantError: errAzureManagedIdentityNoOverride.Error(), wantError: errAzureManagedIdentityNoOverride.Error(),
@ -231,11 +231,11 @@ func TestAzureExtract(t *testing.T) {
}, },
featureGates: configv1.FeatureGates{ featureGates: configv1.FeatureGates{
OpenShift: configv1.OpenShiftFeatureGates{ OpenShift: configv1.OpenShiftFeatureGates{
Enabled: true, Enabled: true,
ManagedAuthEnv: true, TokenCCOAuthEnv: true,
}, },
}, },
wantCredentialMode: lokiv1.CredentialModeManaged, wantCredentialMode: lokiv1.CredentialModeTokenCCO,
}, },
{ {
name: "all set including optional", name: "all set including optional",
@ -554,25 +554,25 @@ func TestS3Extract(t *testing.T) {
} }
} }
func TestS3Extract_WithOpenShiftManagedAuth(t *testing.T) { func TestS3Extract_WithOpenShiftTokenCCOAuth(t *testing.T) {
fg := configv1.FeatureGates{ fg := configv1.FeatureGates{
OpenShift: configv1.OpenShiftFeatureGates{ OpenShift: configv1.OpenShiftFeatureGates{
Enabled: true, Enabled: true,
ManagedAuthEnv: true, TokenCCOAuthEnv: true,
}, },
} }
type test struct { type test struct {
name string name string
secret *corev1.Secret secret *corev1.Secret
managedAuthSecret *corev1.Secret tokenCCOAuthSecret *corev1.Secret
wantError string wantError string
} }
table := []test{ table := []test{
{ {
name: "missing bucketnames", name: "missing bucketnames",
secret: &corev1.Secret{}, secret: &corev1.Secret{},
managedAuthSecret: &corev1.Secret{}, tokenCCOAuthSecret: &corev1.Secret{},
wantError: "missing secret field: bucketnames", wantError: "missing secret field: bucketnames",
}, },
{ {
name: "missing region", name: "missing region",
@ -581,8 +581,8 @@ func TestS3Extract_WithOpenShiftManagedAuth(t *testing.T) {
"bucketnames": []byte("this,that"), "bucketnames": []byte("this,that"),
}, },
}, },
managedAuthSecret: &corev1.Secret{}, tokenCCOAuthSecret: &corev1.Secret{},
wantError: "missing secret field: region", wantError: "missing secret field: region",
}, },
{ {
name: "override role_arn not allowed", name: "override role_arn not allowed",
@ -593,8 +593,8 @@ func TestS3Extract_WithOpenShiftManagedAuth(t *testing.T) {
"role_arn": []byte("role-arn"), "role_arn": []byte("role-arn"),
}, },
}, },
managedAuthSecret: &corev1.Secret{}, tokenCCOAuthSecret: &corev1.Secret{},
wantError: "secret field not allowed: role_arn", wantError: "secret field not allowed: role_arn",
}, },
{ {
name: "STS all set", name: "STS all set",
@ -605,8 +605,8 @@ func TestS3Extract_WithOpenShiftManagedAuth(t *testing.T) {
"region": []byte("a-region"), "region": []byte("a-region"),
}, },
}, },
managedAuthSecret: &corev1.Secret{ tokenCCOAuthSecret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "managed-auth"}, ObjectMeta: metav1.ObjectMeta{Name: "token-cco-auth"},
}, },
}, },
} }
@ -619,16 +619,16 @@ func TestS3Extract_WithOpenShiftManagedAuth(t *testing.T) {
Type: lokiv1.ObjectStorageSecretS3, Type: lokiv1.ObjectStorageSecretS3,
} }
opts, err := extractSecrets(spec, tst.secret, tst.managedAuthSecret, fg) opts, err := extractSecrets(spec, tst.secret, tst.tokenCCOAuthSecret, fg)
if tst.wantError == "" { if tst.wantError == "" {
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, opts.SecretName) require.NotEmpty(t, opts.SecretName)
require.NotEmpty(t, opts.SecretSHA1) require.NotEmpty(t, opts.SecretSHA1)
require.Equal(t, lokiv1.ObjectStorageSecretS3, opts.SharedStore) require.Equal(t, lokiv1.ObjectStorageSecretS3, opts.SharedStore)
require.True(t, opts.S3.STS) require.True(t, opts.S3.STS)
require.Equal(t, tst.managedAuthSecret.Name, opts.OpenShift.CloudCredentials.SecretName) require.Equal(t, tst.tokenCCOAuthSecret.Name, opts.OpenShift.CloudCredentials.SecretName)
require.NotEmpty(t, opts.OpenShift.CloudCredentials.SHA1) require.NotEmpty(t, opts.OpenShift.CloudCredentials.SHA1)
require.Equal(t, lokiv1.CredentialModeManaged, opts.CredentialMode) require.Equal(t, lokiv1.CredentialModeTokenCCO, opts.CredentialMode)
} else { } else {
require.EqualError(t, err, tst.wantError) require.EqualError(t, err, tst.wantError)
} }

@ -20,14 +20,14 @@ import (
// - The object storage schema config is invalid. // - The object storage schema config is invalid.
// - The object storage CA ConfigMap is missing if one referenced. // - The object storage CA ConfigMap is missing if one referenced.
// - The object storage CA ConfigMap data is invalid. // - The object storage CA ConfigMap data is invalid.
// - The object storage managed auth secret is missing (Only on OpenShift STS-clusters) // - The object storage token cco auth secret is missing (Only on OpenShift STS-clusters)
func BuildOptions(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg configv1.FeatureGates) (storage.Options, error) { func BuildOptions(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg configv1.FeatureGates) (storage.Options, error) {
storageSecret, managedAuthSecret, err := getSecrets(ctx, k, stack, fg) storageSecret, tokenCCOAuthSecret, err := getSecrets(ctx, k, stack, fg)
if err != nil { if err != nil {
return storage.Options{}, err return storage.Options{}, err
} }
objStore, err := extractSecrets(stack.Spec.Storage.Secret, storageSecret, managedAuthSecret, fg) objStore, err := extractSecrets(stack.Spec.Storage.Secret, storageSecret, tokenCCOAuthSecret, fg)
if err != nil { if err != nil {
return storage.Options{}, &status.DegradedError{ return storage.Options{}, &status.DegradedError{
Message: fmt.Sprintf("Invalid object storage secret contents: %s", err), Message: fmt.Sprintf("Invalid object storage secret contents: %s", err),
@ -36,11 +36,11 @@ func BuildOptions(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg
} }
} }
if objStore.CredentialMode == lokiv1.CredentialModeManaged && managedAuthSecret == nil { if objStore.CredentialMode == lokiv1.CredentialModeTokenCCO && tokenCCOAuthSecret == nil {
// If we have no managed-auth secret at this point, it is an error // If we have no token cco auth secret at this point, it is an error
return storage.Options{}, &status.DegradedError{ return storage.Options{}, &status.DegradedError{
Message: "Missing OpenShift cloud credentials secret", Message: "Missing OpenShift cloud credentials secret",
Reason: lokiv1.ReasonMissingManagedAuthSecret, Reason: lokiv1.ReasonMissingTokenCCOAuthSecret,
Requeue: true, Requeue: true,
} }
} }

@ -47,7 +47,7 @@ var (
}, },
} }
defaultManagedAuthSecret = corev1.Secret{ defaultTokenCCOAuthSecret = corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "some-stack-secret", Name: "some-stack-secret",
Namespace: "some-ns", Namespace: "some-ns",
@ -147,13 +147,13 @@ func TestBuildOptions_WhenMissingCloudCredentialsSecret_SetDegraded(t *testing.T
fg := configv1.FeatureGates{ fg := configv1.FeatureGates{
OpenShift: configv1.OpenShiftFeatureGates{ OpenShift: configv1.OpenShiftFeatureGates{
ManagedAuthEnv: true, TokenCCOAuthEnv: true,
}, },
} }
degradedErr := &status.DegradedError{ degradedErr := &status.DegradedError{
Message: "Missing OpenShift cloud credentials secret", Message: "Missing OpenShift cloud credentials secret",
Reason: lokiv1.ReasonMissingManagedAuthSecret, Reason: lokiv1.ReasonMissingTokenCCOAuthSecret,
Requeue: true, Requeue: true,
} }
@ -176,7 +176,7 @@ func TestBuildOptions_WhenMissingCloudCredentialsSecret_SetDegraded(t *testing.T
}, },
}, },
Secret: lokiv1.ObjectStorageSecretSpec{ Secret: lokiv1.ObjectStorageSecretSpec{
Name: defaultManagedAuthSecret.Name, Name: defaultTokenCCOAuthSecret.Name,
Type: lokiv1.ObjectStorageSecretS3, Type: lokiv1.ObjectStorageSecretS3,
}, },
}, },
@ -189,8 +189,8 @@ func TestBuildOptions_WhenMissingCloudCredentialsSecret_SetDegraded(t *testing.T
k.SetClientObject(object, stack) k.SetClientObject(object, stack)
return nil return nil
} }
if name.Name == defaultManagedAuthSecret.Name { if name.Name == defaultTokenCCOAuthSecret.Name {
k.SetClientObject(object, &defaultManagedAuthSecret) k.SetClientObject(object, &defaultTokenCCOAuthSecret)
return nil return nil
} }
if name.Name == fmt.Sprintf("%s-aws-creds", stack.Name) { if name.Name == fmt.Sprintf("%s-aws-creds", stack.Name) {

@ -17,7 +17,7 @@ const azureFallbackRegion = "centralus"
func BuildCredentialsRequest(opts Options) (*cloudcredentialv1.CredentialsRequest, error) { func BuildCredentialsRequest(opts Options) (*cloudcredentialv1.CredentialsRequest, error) {
stack := client.ObjectKey{Name: opts.BuildOpts.LokiStackName, Namespace: opts.BuildOpts.LokiStackNamespace} stack := client.ObjectKey{Name: opts.BuildOpts.LokiStackName, Namespace: opts.BuildOpts.LokiStackNamespace}
providerSpec, err := encodeProviderSpec(opts.ManagedAuth) providerSpec, err := encodeProviderSpec(opts.TokenCCOAuth)
if err != nil { if err != nil {
return nil, kverrors.Wrap(err, "failed encoding credentialsrequest provider spec") return nil, kverrors.Wrap(err, "failed encoding credentialsrequest provider spec")
} }
@ -42,7 +42,7 @@ func BuildCredentialsRequest(opts Options) (*cloudcredentialv1.CredentialsReques
}, nil }, nil
} }
func encodeProviderSpec(env *config.ManagedAuthConfig) (*runtime.RawExtension, error) { func encodeProviderSpec(env *config.TokenCCOAuthConfig) (*runtime.RawExtension, error) {
var spec runtime.Object var spec runtime.Object
switch { switch {

@ -15,7 +15,7 @@ func TestBuildCredentialsRequest_HasSecretRef_MatchingLokiStackNamespace(t *test
LokiStackName: "a-stack", LokiStackName: "a-stack",
LokiStackNamespace: "ns", LokiStackNamespace: "ns",
}, },
ManagedAuth: &config.ManagedAuthConfig{ TokenCCOAuth: &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "role-arn", RoleARN: "role-arn",
}, },
@ -33,7 +33,7 @@ func TestBuildCredentialsRequest_HasServiceAccountNames_ContainsAllLokiStackServ
LokiStackName: "a-stack", LokiStackName: "a-stack",
LokiStackNamespace: "ns", LokiStackNamespace: "ns",
}, },
ManagedAuth: &config.ManagedAuthConfig{ TokenCCOAuth: &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "role-arn", RoleARN: "role-arn",
}, },
@ -52,7 +52,7 @@ func TestBuildCredentialsRequest_CloudTokenPath_MatchinOpenShiftSADirectory(t *t
LokiStackName: "a-stack", LokiStackName: "a-stack",
LokiStackNamespace: "ns", LokiStackNamespace: "ns",
}, },
ManagedAuth: &config.ManagedAuthConfig{ TokenCCOAuth: &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "role-arn", RoleARN: "role-arn",
}, },
@ -78,7 +78,7 @@ func TestBuildCredentialsRequest_FollowsNamingConventions(t *testing.T) {
LokiStackName: "a-stack", LokiStackName: "a-stack",
LokiStackNamespace: "ns", LokiStackNamespace: "ns",
}, },
ManagedAuth: &config.ManagedAuthConfig{ TokenCCOAuth: &config.TokenCCOAuthConfig{
AWS: &config.AWSEnvironment{ AWS: &config.AWSEnvironment{
RoleARN: "role-arn", RoleARN: "role-arn",
}, },

@ -15,7 +15,7 @@ type Options struct {
BuildOpts BuildOptions BuildOpts BuildOptions
Authentication []AuthenticationSpec Authentication []AuthenticationSpec
Authorization AuthorizationSpec Authorization AuthorizationSpec
ManagedAuth *config.ManagedAuthConfig TokenCCOAuth *config.TokenCCOAuthConfig
} }
// AuthenticationSpec describes the authentication specification // AuthenticationSpec describes the authentication specification

@ -14,9 +14,9 @@ import (
) )
var ( var (
managedAuthConfigVolumeMount = corev1.VolumeMount{ tokenCCOAuthConfigVolumeMount = corev1.VolumeMount{
Name: managedAuthConfigVolumeName, Name: tokenAuthConfigVolumeName,
MountPath: managedAuthConfigDirectory, MountPath: tokenAuthConfigDirectory,
} }
saTokenVolumeMount = corev1.VolumeMount{ saTokenVolumeMount = corev1.VolumeMount{
@ -136,14 +136,14 @@ func ensureObjectStoreCredentials(p *corev1.PodSpec, opts Options) corev1.PodSpe
MountPath: secretDirectory, MountPath: secretDirectory,
}) })
if managedAuthEnabled(opts) { if tokenAuthEnabled(opts) {
container.Env = append(container.Env, managedAuthCredentials(opts)...) container.Env = append(container.Env, tokenAuthCredentials(opts)...)
volumes = append(volumes, saTokenVolume(opts)) volumes = append(volumes, saTokenVolume(opts))
container.VolumeMounts = append(container.VolumeMounts, saTokenVolumeMount) container.VolumeMounts = append(container.VolumeMounts, saTokenVolumeMount)
if opts.OpenShift.ManagedAuthEnabled() && opts.S3 != nil && opts.S3.STS { if opts.OpenShift.TokenCCOAuthEnabled() && opts.S3 != nil && opts.S3.STS {
volumes = append(volumes, managedAuthConfigVolume(opts)) volumes = append(volumes, tokenCCOAuthConfigVolume(opts))
container.VolumeMounts = append(container.VolumeMounts, managedAuthConfigVolumeMount) container.VolumeMounts = append(container.VolumeMounts, tokenCCOAuthConfigVolumeMount)
} }
} else { } else {
container.Env = append(container.Env, staticAuthCredentials(opts)...) container.Env = append(container.Env, staticAuthCredentials(opts)...)
@ -190,12 +190,12 @@ func staticAuthCredentials(opts Options) []corev1.EnvVar {
} }
} }
func managedAuthCredentials(opts Options) []corev1.EnvVar { func tokenAuthCredentials(opts Options) []corev1.EnvVar {
switch opts.SharedStore { switch opts.SharedStore {
case lokiv1.ObjectStorageSecretS3: case lokiv1.ObjectStorageSecretS3:
if opts.OpenShift.ManagedAuthEnabled() { if opts.OpenShift.TokenCCOAuthEnabled() {
return []corev1.EnvVar{ return []corev1.EnvVar{
envVarFromValue(EnvAWSCredentialsFile, path.Join(managedAuthConfigDirectory, KeyAWSCredentialsFilename)), envVarFromValue(EnvAWSCredentialsFile, path.Join(tokenAuthConfigDirectory, KeyAWSCredentialsFilename)),
envVarFromValue(EnvAWSSdkLoadConfig, "true"), envVarFromValue(EnvAWSSdkLoadConfig, "true"),
} }
} else { } else {
@ -205,7 +205,7 @@ func managedAuthCredentials(opts Options) []corev1.EnvVar {
} }
} }
case lokiv1.ObjectStorageSecretAzure: case lokiv1.ObjectStorageSecretAzure:
if opts.OpenShift.ManagedAuthEnabled() { if opts.OpenShift.TokenCCOAuthEnabled() {
return []corev1.EnvVar{ return []corev1.EnvVar{
envVarFromSecret(EnvAzureStorageAccountName, opts.SecretName, KeyAzureStorageAccountName), envVarFromSecret(EnvAzureStorageAccountName, opts.SecretName, KeyAzureStorageAccountName),
envVarFromSecret(EnvAzureClientID, opts.OpenShift.CloudCredentials.SecretName, azureManagedCredentialKeyClientID), envVarFromSecret(EnvAzureClientID, opts.OpenShift.CloudCredentials.SecretName, azureManagedCredentialKeyClientID),
@ -300,9 +300,9 @@ func envVarFromValue(name, value string) corev1.EnvVar {
} }
} }
func managedAuthEnabled(opts Options) bool { func tokenAuthEnabled(opts Options) bool {
switch opts.CredentialMode { switch opts.CredentialMode {
case lokiv1.CredentialModeToken, lokiv1.CredentialModeManaged: case lokiv1.CredentialModeToken, lokiv1.CredentialModeTokenCCO:
return true return true
case lokiv1.CredentialModeStatic: case lokiv1.CredentialModeStatic:
fallthrough fallthrough
@ -346,9 +346,9 @@ func saTokenVolume(opts Options) corev1.Volume {
} }
} }
func managedAuthConfigVolume(opts Options) corev1.Volume { func tokenCCOAuthConfigVolume(opts Options) corev1.Volume {
return corev1.Volume{ return corev1.Volume{
Name: managedAuthConfigVolumeName, Name: tokenAuthConfigVolumeName,
VolumeSource: corev1.VolumeSource{ VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{ Secret: &corev1.SecretVolumeSource{
SecretName: opts.OpenShift.CloudCredentials.SecretName, SecretName: opts.OpenShift.CloudCredentials.SecretName,

@ -424,7 +424,7 @@ func TestConfigureDeploymentForStorageType(t *testing.T) {
opts: Options{ opts: Options{
SecretName: "test", SecretName: "test",
SharedStore: lokiv1.ObjectStorageSecretAzure, SharedStore: lokiv1.ObjectStorageSecretAzure,
CredentialMode: lokiv1.CredentialModeManaged, CredentialMode: lokiv1.CredentialModeTokenCCO,
Azure: &AzureStorageConfig{ Azure: &AzureStorageConfig{
WorkloadIdentity: true, WorkloadIdentity: true,
}, },
@ -861,7 +861,7 @@ func TestConfigureDeploymentForStorageType(t *testing.T) {
opts: Options{ opts: Options{
SecretName: "test", SecretName: "test",
SharedStore: lokiv1.ObjectStorageSecretS3, SharedStore: lokiv1.ObjectStorageSecretS3,
CredentialMode: lokiv1.CredentialModeManaged, CredentialMode: lokiv1.CredentialModeTokenCCO,
S3: &S3StorageConfig{ S3: &S3StorageConfig{
STS: true, STS: true,
}, },
@ -904,12 +904,12 @@ func TestConfigureDeploymentForStorageType(t *testing.T) {
ReadOnly: false, ReadOnly: false,
MountPath: saTokenVolumeMountPath, MountPath: saTokenVolumeMountPath,
}, },
managedAuthConfigVolumeMount, tokenCCOAuthConfigVolumeMount,
}, },
Env: []corev1.EnvVar{ Env: []corev1.EnvVar{
{ {
Name: "AWS_SHARED_CREDENTIALS_FILE", Name: "AWS_SHARED_CREDENTIALS_FILE",
Value: "/etc/storage/managed-auth/credentials", Value: "/etc/storage/token-auth/credentials",
}, },
{ {
Name: "AWS_SDK_LOAD_CONFIG", Name: "AWS_SDK_LOAD_CONFIG",
@ -944,7 +944,7 @@ func TestConfigureDeploymentForStorageType(t *testing.T) {
}, },
}, },
{ {
Name: managedAuthConfigVolumeName, Name: tokenAuthConfigVolumeName,
VolumeSource: corev1.VolumeSource{ VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{ Secret: &corev1.SecretVolumeSource{
SecretName: "cloud-credentials", SecretName: "cloud-credentials",
@ -1623,7 +1623,7 @@ func TestConfigureStatefulSetForStorageType(t *testing.T) {
opts: Options{ opts: Options{
SecretName: "test", SecretName: "test",
SharedStore: lokiv1.ObjectStorageSecretAzure, SharedStore: lokiv1.ObjectStorageSecretAzure,
CredentialMode: lokiv1.CredentialModeManaged, CredentialMode: lokiv1.CredentialModeTokenCCO,
Azure: &AzureStorageConfig{ Azure: &AzureStorageConfig{
WorkloadIdentity: true, WorkloadIdentity: true,
}, },
@ -1811,7 +1811,7 @@ func TestConfigureStatefulSetForStorageType(t *testing.T) {
opts: Options{ opts: Options{
SecretName: "test", SecretName: "test",
SharedStore: lokiv1.ObjectStorageSecretGCS, SharedStore: lokiv1.ObjectStorageSecretGCS,
CredentialMode: lokiv1.CredentialModeManaged, CredentialMode: lokiv1.CredentialModeTokenCCO,
GCS: &GCSStorageConfig{ GCS: &GCSStorageConfig{
Audience: "test", Audience: "test",
WorkloadIdentity: true, WorkloadIdentity: true,
@ -1967,7 +1967,7 @@ func TestConfigureStatefulSetForStorageType(t *testing.T) {
opts: Options{ opts: Options{
SecretName: "test", SecretName: "test",
SharedStore: lokiv1.ObjectStorageSecretS3, SharedStore: lokiv1.ObjectStorageSecretS3,
CredentialMode: lokiv1.CredentialModeManaged, CredentialMode: lokiv1.CredentialModeTokenCCO,
S3: &S3StorageConfig{ S3: &S3StorageConfig{
STS: true, STS: true,
}, },
@ -2010,12 +2010,12 @@ func TestConfigureStatefulSetForStorageType(t *testing.T) {
ReadOnly: false, ReadOnly: false,
MountPath: saTokenVolumeMountPath, MountPath: saTokenVolumeMountPath,
}, },
managedAuthConfigVolumeMount, tokenCCOAuthConfigVolumeMount,
}, },
Env: []corev1.EnvVar{ Env: []corev1.EnvVar{
{ {
Name: "AWS_SHARED_CREDENTIALS_FILE", Name: "AWS_SHARED_CREDENTIALS_FILE",
Value: "/etc/storage/managed-auth/credentials", Value: "/etc/storage/token-auth/credentials",
}, },
{ {
Name: "AWS_SDK_LOAD_CONFIG", Name: "AWS_SDK_LOAD_CONFIG",
@ -2050,7 +2050,7 @@ func TestConfigureStatefulSetForStorageType(t *testing.T) {
}, },
}, },
{ {
Name: managedAuthConfigVolumeName, Name: tokenAuthConfigVolumeName,
VolumeSource: corev1.VolumeSource{ VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{ Secret: &corev1.SecretVolumeSource{
SecretName: "cloud-credentials", SecretName: "cloud-credentials",

@ -102,6 +102,6 @@ type CloudCredentials struct {
SHA1 string SHA1 string
} }
func (o OpenShiftOptions) ManagedAuthEnabled() bool { func (o OpenShiftOptions) TokenCCOAuthEnabled() bool {
return o.CloudCredentials.SecretName != "" && o.CloudCredentials.SHA1 != "" return o.CloudCredentials.SecretName != "" && o.CloudCredentials.SHA1 != ""
} }

@ -137,8 +137,8 @@ const (
storageTLSVolume = "storage-tls" storageTLSVolume = "storage-tls"
caDirectory = "/etc/storage/ca" caDirectory = "/etc/storage/ca"
managedAuthConfigVolumeName = "managed-auth-config" tokenAuthConfigVolumeName = "token-auth-config"
managedAuthConfigDirectory = "/etc/storage/managed-auth" tokenAuthConfigDirectory = "/etc/storage/token-auth"
awsDefaultAudience = "sts.amazonaws.com" awsDefaultAudience = "sts.amazonaws.com"

@ -78,8 +78,8 @@ const (
AnnotationLokiConfigHash string = "loki.grafana.com/config-hash" AnnotationLokiConfigHash string = "loki.grafana.com/config-hash"
// AnnotationLokiObjectStoreHash stores the last SHA1 hash of the loki object storage credetials. // AnnotationLokiObjectStoreHash stores the last SHA1 hash of the loki object storage credetials.
AnnotationLokiObjectStoreHash string = "loki.grafana.com/object-store-hash" AnnotationLokiObjectStoreHash string = "loki.grafana.com/object-store-hash"
// AnnotationLokiManagedAuthHash stores the last SHA1 hash of the loki managed auth credentials. // AnnotationLokiTokenCCOAuthHash stores the SHA1 hash of the secret generated by the Cloud Credential Operator.
AnnotationLokiManagedAuthHash string = "loki.grafana.com/managed-auth-hash" AnnotationLokiTokenCCOAuthHash string = "loki.grafana.com/token-cco-auth-hash"
// LabelCompactorComponent is the label value for the compactor component // LabelCompactorComponent is the label value for the compactor component
LabelCompactorComponent string = "compactor" LabelCompactorComponent string = "compactor"
@ -145,7 +145,7 @@ func commonAnnotations(opts Options) map[string]string {
a[AnnotationLokiObjectStoreHash] = opts.ObjectStorage.SecretSHA1 a[AnnotationLokiObjectStoreHash] = opts.ObjectStorage.SecretSHA1
} }
if opts.ObjectStorage.OpenShift.CloudCredentials.SHA1 != "" { if opts.ObjectStorage.OpenShift.CloudCredentials.SHA1 != "" {
a[AnnotationLokiManagedAuthHash] = opts.ObjectStorage.OpenShift.CloudCredentials.SHA1 a[AnnotationLokiTokenCCOAuthHash] = opts.ObjectStorage.OpenShift.CloudCredentials.SHA1
} }
return a return a

@ -59,14 +59,14 @@ func main() {
var err error var err error
ctrlCfg, managedAuth, options, err := config.LoadConfig(scheme, configFile) ctrlCfg, tokenCCOAuth, options, err := config.LoadConfig(scheme, configFile)
if err != nil { if err != nil {
logger.Error(err, "failed to load operator configuration") logger.Error(err, "failed to load operator configuration")
os.Exit(1) os.Exit(1)
} }
if managedAuth != nil { if tokenCCOAuth != nil {
logger.Info("Discovered OpenShift Cluster within a managed authentication environment") logger.Info("Discovered OpenShift Cluster within a token cco authentication environment")
} }
if ctrlCfg.Gates.LokiStackAlerts && !ctrlCfg.Gates.ServiceMonitors { if ctrlCfg.Gates.LokiStackAlerts && !ctrlCfg.Gates.ServiceMonitors {
@ -103,7 +103,7 @@ func main() {
Log: logger.WithName("controllers").WithName("lokistack"), Log: logger.WithName("controllers").WithName("lokistack"),
Scheme: mgr.GetScheme(), Scheme: mgr.GetScheme(),
FeatureGates: ctrlCfg.Gates, FeatureGates: ctrlCfg.Gates,
AuthConfig: managedAuth, AuthConfig: tokenCCOAuth,
}).SetupWithManager(mgr); err != nil { }).SetupWithManager(mgr); err != nil {
logger.Error(err, "unable to create controller", "controller", "lokistack") logger.Error(err, "unable to create controller", "controller", "lokistack")
os.Exit(1) os.Exit(1)

Loading…
Cancel
Save