diff --git a/operator/apis/loki/v1/rulerconfig_types.go b/operator/apis/loki/v1/rulerconfig_types.go index d8ca91523da8..8321d2bc6701 100644 --- a/operator/apis/loki/v1/rulerconfig_types.go +++ b/operator/apis/loki/v1/rulerconfig_types.go @@ -221,6 +221,13 @@ type AlertManagerClientTLSConfig struct { // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Key Path" KeyPath *string `json:"keyPath,omitempty"` + + // Skip validating server certificate. + // + // +optional + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Skip validating server certificate" + InsecureSkipVerify *bool `json:"insecureSkipVerify,omitempty"` } // RemoteWriteAuthType defines the type of authorization to use to access the remote write endpoint. diff --git a/operator/apis/loki/v1/zz_generated.deepcopy.go b/operator/apis/loki/v1/zz_generated.deepcopy.go index 03b8e5ad0b9e..c7206c5ab660 100644 --- a/operator/apis/loki/v1/zz_generated.deepcopy.go +++ b/operator/apis/loki/v1/zz_generated.deepcopy.go @@ -118,6 +118,11 @@ func (in *AlertManagerClientTLSConfig) DeepCopyInto(out *AlertManagerClientTLSCo *out = new(string) **out = **in } + if in.InsecureSkipVerify != nil { + in, out := &in.InsecureSkipVerify, &out.InsecureSkipVerify + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlertManagerClientTLSConfig. diff --git a/operator/config/crd/bases/loki.grafana.com_rulerconfigs.yaml b/operator/config/crd/bases/loki.grafana.com_rulerconfigs.yaml index 88d65fb826c7..df922bfdefd1 100644 --- a/operator/config/crd/bases/loki.grafana.com_rulerconfigs.yaml +++ b/operator/config/crd/bases/loki.grafana.com_rulerconfigs.yaml @@ -89,6 +89,9 @@ spec: description: The client-side certificate file path for the TLS configuration. type: string + insecureSkipVerify: + description: Skip validating server certificate. + type: boolean keyPath: description: The client-side key file path for the TLS configuration. @@ -292,6 +295,9 @@ spec: description: The client-side certificate file path for the TLS configuration. type: string + insecureSkipVerify: + description: Skip validating server certificate. + type: boolean keyPath: description: The client-side key file path for the TLS configuration. diff --git a/operator/internal/manifests/config.go b/operator/internal/manifests/config.go index 4ec0b728d916..e212e6d6a30f 100644 --- a/operator/internal/manifests/config.go +++ b/operator/internal/manifests/config.go @@ -248,10 +248,11 @@ func alertManagerConfig(spec *lokiv1.AlertManagerSpec) *config.AlertManagerConfi conf.Notifier = &config.NotifierConfig{} if tls := clt.TLS; tls != nil { conf.Notifier.TLS = config.TLSConfig{ - CAPath: tls.CAPath, - ServerName: tls.ServerName, - CertPath: tls.CertPath, - KeyPath: tls.KeyPath, + CAPath: tls.CAPath, + ServerName: tls.ServerName, + InsecureSkipVerify: tls.InsecureSkipVerify, + CertPath: tls.CertPath, + KeyPath: tls.KeyPath, } } diff --git a/operator/internal/manifests/internal/config/build_test.go b/operator/internal/manifests/internal/config/build_test.go index 1d9a0287b398..9486771f2611 100644 --- a/operator/internal/manifests/internal/config/build_test.go +++ b/operator/internal/manifests/internal/config/build_test.go @@ -5632,3 +5632,391 @@ analytics: require.NoError(t, err) require.YAMLEq(t, expCfg, string(cfg)) } + +func TestBuild_ConfigAndRuntimeConfig_RulerConfigGenerated_WithAlertmanagerClient(t *testing.T) { + expCfg := ` +--- +auth_enabled: true +chunk_store_config: + chunk_cache_config: + embedded_cache: + enabled: true + max_size_mb: 500 +common: + storage: + s3: + endpoint: http://test.default.svc.cluster.local.:9000 + bucketnames: loki + region: us-east + access_key_id: ${AWS_ACCESS_KEY_ID} + secret_access_key: ${AWS_ACCESS_KEY_SECRET} + s3forcepathstyle: true + compactor_grpc_address: loki-compactor-grpc-lokistack-dev.default.svc.cluster.local:9095 + ring: + kvstore: + store: memberlist + heartbeat_period: 5s + heartbeat_timeout: 1m + instance_port: 9095 +compactor: + compaction_interval: 2h + working_directory: /tmp/loki/compactor +frontend: + tail_proxy_url: http://loki-querier-http-lokistack-dev.default.svc.cluster.local:3100 + compress_responses: true + max_outstanding_per_tenant: 4096 + log_queries_longer_than: 5s +frontend_worker: + frontend_address: loki-query-frontend-grpc-lokistack-dev.default.svc.cluster.local:9095 + grpc_client_config: + max_send_msg_size: 104857600 + match_max_concurrent: true +ingester: + chunk_block_size: 262144 + chunk_encoding: snappy + chunk_idle_period: 1h + chunk_retain_period: 5m + chunk_target_size: 2097152 + flush_op_timeout: 10m + lifecycler: + final_sleep: 0s + join_after: 30s + num_tokens: 512 + ring: + replication_factor: 1 + max_chunk_age: 2h + max_transfer_retries: 0 + wal: + enabled: true + dir: /tmp/wal + replay_memory_ceiling: 2147483648 +ingester_client: + grpc_client_config: + max_recv_msg_size: 67108864 + remote_timeout: 1s +# NOTE: Keep the order of keys as in Loki docs +# to enable easy diffs when vendoring newer +# Loki releases. +# (See https://grafana.com/docs/loki/latest/configuration/#limits_config) +# +# Values for not exposed fields are taken from the grafana/loki production +# configuration manifests. +# (See https://github.com/grafana/loki/blob/main/production/ksonnet/loki/config.libsonnet) +limits_config: + ingestion_rate_strategy: global + ingestion_rate_mb: 4 + ingestion_burst_size_mb: 6 + max_label_name_length: 1024 + max_label_value_length: 2048 + max_label_names_per_series: 30 + reject_old_samples: true + reject_old_samples_max_age: 168h + creation_grace_period: 10m + enforce_metric_name: false + # Keep max_streams_per_user always to 0 to default + # using max_global_streams_per_user always. + # (See https://github.com/grafana/loki/blob/main/pkg/ingester/limiter.go#L73) + max_streams_per_user: 0 + max_line_size: 256000 + max_entries_limit_per_query: 5000 + max_global_streams_per_user: 0 + max_chunks_per_query: 2000000 + max_query_length: 721h + max_query_parallelism: 32 + tsdb_max_query_parallelism: 512 + max_query_series: 500 + cardinality_limit: 100000 + max_streams_matchers_per_query: 1000 + max_cache_freshness_per_query: 10m + split_queries_by_interval: 30m + query_timeout: 1m + per_stream_rate_limit: 5MB + per_stream_rate_limit_burst: 15MB + shard_streams: + enabled: true + desired_rate: 3MB + allow_structured_metadata: true +memberlist: + abort_if_cluster_join_fails: true + advertise_port: 7946 + bind_port: 7946 + join_members: + - loki-gossip-ring-lokistack-dev.default.svc.cluster.local:7946 + max_join_backoff: 1m + max_join_retries: 10 + min_join_backoff: 1s +querier: + engine: + max_look_back_period: 30s + extra_query_delay: 0s + max_concurrent: 2 + query_ingesters_within: 3h + tail_max_duration: 1h +query_range: + align_queries_with_step: true + cache_results: true + max_retries: 5 + results_cache: + cache: + embedded_cache: + enabled: true + max_size_mb: 500 + parallelise_shardable_queries: true +schema_config: + configs: + - from: "2020-10-01" + index: + period: 24h + prefix: index_ + object_store: s3 + schema: v11 + store: boltdb-shipper +ruler: + enable_api: true + enable_sharding: true + evaluation_interval: 1m + poll_interval: 1m + external_url: http://alert.me/now + external_labels: + key1: val1 + key2: val2 + alertmanager_url: http://alerthost1,http://alerthost2 + enable_alertmanager_v2: true + enable_alertmanager_discovery: true + alertmanager_refresh_interval: 1m + notification_queue_capacity: 1000 + notification_timeout: 1m + alertmanager_client: + tls_cert_path: "custom/path" + tls_key_path: "custom/key" + tls_ca_path: "custom/CA" + tls_server_name: "custom-servername" + tls_insecure_skip_verify: false + basic_auth_password: "pass" + basic_auth_username: "user" + credentials: "creds" + credentials_file: "cred/file" + type: "auth" + for_outage_tolerance: 10m + for_grace_period: 5m + resend_delay: 2m + remote_write: + enabled: true + config_refresh_period: 1m + client: + name: remote-write-me + url: http://remote.write.me + remote_timeout: 10s + proxy_url: http://proxy.through.me + follow_redirects: true + headers: + more: foryou + less: forme + authorization: + type: bearer + credentials: supersecret + queue_config: + capacity: 1000 + max_shards: 100 + min_shards: 50 + max_samples_per_send: 1000 + batch_send_deadline: 10s + min_backoff: 30ms + max_backoff: 100ms + wal: + dir: /tmp/wal + truncate_frequency: 60m + min_age: 5m + max_age: 4h + rule_path: /tmp/loki + storage: + type: local + local: + directory: /tmp/rules + ring: + kvstore: + store: memberlist +server: + graceful_shutdown_timeout: 5s + grpc_server_min_time_between_pings: '10s' + grpc_server_ping_without_stream_allowed: true + grpc_server_max_concurrent_streams: 1000 + grpc_server_max_recv_msg_size: 104857600 + grpc_server_max_send_msg_size: 104857600 + http_listen_port: 3100 + http_server_idle_timeout: 30s + http_server_read_timeout: 30s + http_server_write_timeout: 10m0s + log_level: info +storage_config: + boltdb_shipper: + active_index_directory: /tmp/loki/index + cache_location: /tmp/loki/index_cache + cache_ttl: 24h + resync_interval: 5m + shared_store: s3 + index_gateway_client: + server_address: dns:///loki-index-gateway-grpc-lokistack-dev.default.svc.cluster.local:9095 +tracing: + enabled: false +analytics: + reporting_enabled: true +` + expRCfg := ` +--- +overrides: +` + opts := Options{ + Stack: lokiv1.LokiStackSpec{ + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, + Limits: &lokiv1.LimitsSpec{ + Global: &lokiv1.LimitsTemplateSpec{ + IngestionLimits: &lokiv1.IngestionLimitSpec{ + IngestionRate: 4, + IngestionBurstSize: 6, + MaxLabelNameLength: 1024, + MaxLabelValueLength: 2048, + MaxLabelNamesPerSeries: 30, + MaxGlobalStreamsPerTenant: 0, + MaxLineSize: 256000, + PerStreamRateLimit: 5, + PerStreamRateLimitBurst: 15, + PerStreamDesiredRate: 3, + }, + QueryLimits: &lokiv1.QueryLimitSpec{ + MaxEntriesLimitPerQuery: 5000, + MaxChunksPerQuery: 2000000, + MaxQuerySeries: 500, + QueryTimeout: "1m", + CardinalityLimit: 100000, + }, + }, + }, + }, + Namespace: "test-ns", + Name: "test", + Compactor: Address{ + FQDN: "loki-compactor-grpc-lokistack-dev.default.svc.cluster.local", + Port: 9095, + }, + FrontendWorker: Address{ + FQDN: "loki-query-frontend-grpc-lokistack-dev.default.svc.cluster.local", + Port: 9095, + }, + GossipRing: GossipRing{ + InstancePort: 9095, + BindPort: 7946, + MembersDiscoveryAddr: "loki-gossip-ring-lokistack-dev.default.svc.cluster.local", + }, + Querier: Address{ + Protocol: "http", + FQDN: "loki-querier-http-lokistack-dev.default.svc.cluster.local", + Port: 3100, + }, + IndexGateway: Address{ + FQDN: "loki-index-gateway-grpc-lokistack-dev.default.svc.cluster.local", + Port: 9095, + }, + Ruler: Ruler{ + Enabled: true, + RulesStorageDirectory: "/tmp/rules", + EvaluationInterval: "1m", + PollInterval: "1m", + AlertManager: &AlertManagerConfig{ + Notifier: &NotifierConfig{ + TLS: TLSConfig{ + ServerName: ptr.To("custom-servername"), + CertPath: ptr.To("custom/path"), + KeyPath: ptr.To("custom/key"), + CAPath: ptr.To("custom/CA"), + InsecureSkipVerify: ptr.To(false), + }, + BasicAuth: BasicAuth{ + Username: ptr.To("user"), + Password: ptr.To("pass"), + }, + HeaderAuth: HeaderAuth{ + CredentialsFile: ptr.To("cred/file"), + Type: ptr.To("auth"), + Credentials: ptr.To("creds"), + }, + }, + ExternalURL: "http://alert.me/now", + ExternalLabels: map[string]string{ + "key1": "val1", + "key2": "val2", + }, + Hosts: "http://alerthost1,http://alerthost2", + EnableV2: true, + EnableDiscovery: true, + RefreshInterval: "1m", + QueueCapacity: 1000, + Timeout: "1m", + ForOutageTolerance: "10m", + ForGracePeriod: "5m", + ResendDelay: "2m", + }, + RemoteWrite: &RemoteWriteConfig{ + Enabled: true, + RefreshPeriod: "1m", + Client: &RemoteWriteClientConfig{ + Name: "remote-write-me", + URL: "http://remote.write.me", + RemoteTimeout: "10s", + Headers: map[string]string{ + "more": "foryou", + "less": "forme", + }, + ProxyURL: "http://proxy.through.me", + FollowRedirects: true, + BearerToken: "supersecret", + }, + Queue: &RemoteWriteQueueConfig{ + Capacity: 1000, + MaxShards: 100, + MinShards: 50, + MaxSamplesPerSend: 1000, + BatchSendDeadline: "10s", + MinBackOffPeriod: "30ms", + MaxBackOffPeriod: "100ms", + }, + }, + }, + StorageDirectory: "/tmp/loki", + MaxConcurrent: MaxConcurrent{ + AvailableQuerierCPUCores: 2, + }, + WriteAheadLog: WriteAheadLog{ + Directory: "/tmp/wal", + IngesterMemoryRequest: 4 * 1024 * 1024 * 1024, + }, + ObjectStorage: storage.Options{ + SharedStore: lokiv1.ObjectStorageSecretS3, + S3: &storage.S3StorageConfig{ + Endpoint: "http://test.default.svc.cluster.local.:9000", + Region: "us-east", + Buckets: "loki", + ForcePathStyle: true, + }, + Schemas: []lokiv1.ObjectStorageSchema{ + { + Version: lokiv1.ObjectStorageSchemaV11, + EffectiveDate: "2020-10-01", + }, + }, + }, + Shippers: []string{"boltdb"}, + EnableRemoteReporting: true, + HTTPTimeouts: HTTPTimeoutConfig{ + IdleTimeout: 30 * time.Second, + ReadTimeout: 30 * time.Second, + WriteTimeout: 10 * time.Minute, + }, + } + cfg, rCfg, err := Build(opts) + require.NoError(t, err) + require.YAMLEq(t, expCfg, string(cfg)) + require.YAMLEq(t, expRCfg, string(rCfg)) +} diff --git a/operator/internal/manifests/internal/config/loki-config.yaml b/operator/internal/manifests/internal/config/loki-config.yaml index 3df0ac746388..38326157f293 100644 --- a/operator/internal/manifests/internal/config/loki-config.yaml +++ b/operator/internal/manifests/internal/config/loki-config.yaml @@ -313,6 +313,47 @@ ruler: {{- if .Timeout }} notification_timeout: {{ .Timeout }} {{- end }} + {{- if .Notifier }} + {{- with .Notifier }} + alertmanager_client: + {{- if .TLS.CertPath }} + tls_cert_path: {{ .TLS.CertPath }} + {{- end }} + {{- if .TLS.KeyPath }} + tls_key_path: {{ .TLS.KeyPath }} + {{- end }} + {{- if .TLS.CAPath }} + tls_ca_path: {{ .TLS.CAPath }} + {{- end }} + {{- if .TLS.ServerName }} + tls_server_name: {{ .TLS.ServerName }} + {{- end }} + {{- if .TLS.InsecureSkipVerify }} + tls_insecure_skip_verify: {{ .TLS.InsecureSkipVerify }} + {{- end }} + {{- if .TLS.CipherSuites }} + tls_cipher_suites: {{ .TLS.CipherSuites }} + {{- end }} + {{- if .TLS.MinVersion }} + tls_min_version: {{ .TLS.MinVersion }} + {{- end }} + {{- if .BasicAuth.Username }} + basic_auth_username: {{ .BasicAuth.Username }} + {{- end }} + {{- if .BasicAuth.Password }} + basic_auth_password: {{ .BasicAuth.Password }} + {{- end }} + {{- if .HeaderAuth.Type }} + type: {{ .HeaderAuth.Type }} + {{- end }} + {{- if .HeaderAuth.Credentials }} + credentials: {{ .HeaderAuth.Credentials }} + {{- end }} + {{- if .HeaderAuth.CredentialsFile }} + credentials_file: {{ .HeaderAuth.CredentialsFile }} + {{- end }} + {{- end }} + {{- end }} {{- with .RelabelConfigs }} alert_relabel_configs: