@bluedynamics/cdk8s-monitoring 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +76 -0
- package/LICENSE +202 -0
- package/README.md +87 -0
- package/examples/synth.ts +17 -0
- package/lib/constructs/alloy.d.ts +29 -0
- package/lib/constructs/alloy.js +214 -0
- package/lib/constructs/grafana-password-secret.d.ts +57 -0
- package/lib/constructs/grafana-password-secret.js +99 -0
- package/lib/constructs/loki-s3-bucket.d.ts +24 -0
- package/lib/constructs/loki-s3-bucket.js +147 -0
- package/lib/constructs/loki-s3-credentials.d.ts +27 -0
- package/lib/constructs/loki-s3-credentials.js +71 -0
- package/lib/constructs/loki.d.ts +30 -0
- package/lib/constructs/loki.js +185 -0
- package/lib/constructs/namespace.d.ts +13 -0
- package/lib/constructs/namespace.js +34 -0
- package/lib/constructs/priority-class.d.ts +12 -0
- package/lib/constructs/priority-class.js +38 -0
- package/lib/constructs/prometheus-stack.d.ts +30 -0
- package/lib/constructs/prometheus-stack.js +477 -0
- package/lib/constructs/thanos-compactor.d.ts +35 -0
- package/lib/constructs/thanos-compactor.js +198 -0
- package/lib/constructs/thanos-query.d.ts +30 -0
- package/lib/constructs/thanos-query.js +205 -0
- package/lib/constructs/thanos-s3-bucket.d.ts +24 -0
- package/lib/constructs/thanos-s3-bucket.js +147 -0
- package/lib/constructs/thanos-s3-credentials.d.ts +27 -0
- package/lib/constructs/thanos-s3-credentials.js +93 -0
- package/lib/constructs/thanos-store.d.ts +30 -0
- package/lib/constructs/thanos-store.js +239 -0
- package/lib/default-config.d.ts +12 -0
- package/lib/default-config.js +77 -0
- package/lib/imports/external-secrets.io.d.ts +39243 -0
- package/lib/imports/external-secrets.io.js +23112 -0
- package/lib/imports/generators.external-secrets.io.d.ts +7831 -0
- package/lib/imports/generators.external-secrets.io.js +4895 -0
- package/lib/imports/k8s.d.ts +24537 -0
- package/lib/imports/k8s.js +18268 -0
- package/lib/imports/s3.aws.upbound.io.d.ts +2882 -0
- package/lib/imports/s3.aws.upbound.io.js +1828 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.js +38 -0
- package/lib/monitoring-chart.d.ts +39 -0
- package/lib/monitoring-chart.js +127 -0
- package/lib/types.d.ts +142 -0
- package/lib/types.js +3 -0
- package/package.json +117 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import { ExternalSecret } from '../imports/external-secrets.io';
|
|
3
|
+
export interface GrafanaPasswordSecretProps {
|
|
4
|
+
readonly namespace: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Creates ExternalSecret for stable Grafana admin credentials.
|
|
8
|
+
*
|
|
9
|
+
* This construct creates an ExternalSecret that replicates the Grafana admin password
|
|
10
|
+
* from the application-secrets namespace to the monitoring namespace, following the
|
|
11
|
+
* centralized secret management pattern.
|
|
12
|
+
*
|
|
13
|
+
* Prerequisites:
|
|
14
|
+
* - External Secrets Operator installed
|
|
15
|
+
* - ClusterSecretStore 'monitoring-app-secrets-store' exists (points to application-secrets)
|
|
16
|
+
* - Secret 'grafana-admin' exists in application-secrets namespace with keys:
|
|
17
|
+
* - admin-user
|
|
18
|
+
* - admin-password
|
|
19
|
+
*
|
|
20
|
+
* Security Model:
|
|
21
|
+
* - Source secret stored in centralized application-secrets namespace
|
|
22
|
+
* - ExternalSecret CR (this) committed to git (GitOps-safe, no password in git)
|
|
23
|
+
* - ESO automatically replicates secret to monitoring namespace
|
|
24
|
+
* - Password persists across Helm upgrades (no auto-regeneration)
|
|
25
|
+
*
|
|
26
|
+
* Benefits:
|
|
27
|
+
* - Centralized secret management (all app secrets in application-secrets namespace)
|
|
28
|
+
* - GitOps-safe (ExternalSecret in git, actual password not in git)
|
|
29
|
+
* - Password rotation (update source → auto-sync to monitoring)
|
|
30
|
+
* - Follows GitLab BDA security model (see documentation/sources/deployments/gitlabbda/explanation/security-model.md)
|
|
31
|
+
*
|
|
32
|
+
* Usage in prometheus-stack.ts:
|
|
33
|
+
* ```yaml
|
|
34
|
+
* grafana:
|
|
35
|
+
* admin:
|
|
36
|
+
* existingSecret: "grafana-admin-credentials"
|
|
37
|
+
* userKey: "admin-user"
|
|
38
|
+
* passwordKey: "admin-password"
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* Manual Setup Required:
|
|
42
|
+
* 1. Create source secret in application-secrets namespace:
|
|
43
|
+
* ```bash
|
|
44
|
+
* kubectl create secret generic grafana-admin -n application-secrets \
|
|
45
|
+
* --from-literal=admin-user=admin \
|
|
46
|
+
* --from-literal=admin-password='YourSecurePassword123!'
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* 2. Create ClusterSecretStore (if not exists):
|
|
50
|
+
* See: documentation/sources/deployments/monitoring/how-to/setup-grafana-password.md
|
|
51
|
+
*
|
|
52
|
+
* 3. Deploy monitoring stack (this ExternalSecret will sync the secret)
|
|
53
|
+
*/
|
|
54
|
+
export declare class GrafanaPasswordSecret extends Construct {
|
|
55
|
+
readonly externalSecret: ExternalSecret;
|
|
56
|
+
constructor(scope: Construct, id: string, props: GrafanaPasswordSecretProps);
|
|
57
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GrafanaPasswordSecret = void 0;
|
|
4
|
+
const constructs_1 = require("constructs");
|
|
5
|
+
const external_secrets_io_1 = require("../imports/external-secrets.io");
|
|
6
|
+
/**
|
|
7
|
+
* Creates ExternalSecret for stable Grafana admin credentials.
|
|
8
|
+
*
|
|
9
|
+
* This construct creates an ExternalSecret that replicates the Grafana admin password
|
|
10
|
+
* from the application-secrets namespace to the monitoring namespace, following the
|
|
11
|
+
* centralized secret management pattern.
|
|
12
|
+
*
|
|
13
|
+
* Prerequisites:
|
|
14
|
+
* - External Secrets Operator installed
|
|
15
|
+
* - ClusterSecretStore 'monitoring-app-secrets-store' exists (points to application-secrets)
|
|
16
|
+
* - Secret 'grafana-admin' exists in application-secrets namespace with keys:
|
|
17
|
+
* - admin-user
|
|
18
|
+
* - admin-password
|
|
19
|
+
*
|
|
20
|
+
* Security Model:
|
|
21
|
+
* - Source secret stored in centralized application-secrets namespace
|
|
22
|
+
* - ExternalSecret CR (this) committed to git (GitOps-safe, no password in git)
|
|
23
|
+
* - ESO automatically replicates secret to monitoring namespace
|
|
24
|
+
* - Password persists across Helm upgrades (no auto-regeneration)
|
|
25
|
+
*
|
|
26
|
+
* Benefits:
|
|
27
|
+
* - Centralized secret management (all app secrets in application-secrets namespace)
|
|
28
|
+
* - GitOps-safe (ExternalSecret in git, actual password not in git)
|
|
29
|
+
* - Password rotation (update source → auto-sync to monitoring)
|
|
30
|
+
* - Follows GitLab BDA security model (see documentation/sources/deployments/gitlabbda/explanation/security-model.md)
|
|
31
|
+
*
|
|
32
|
+
* Usage in prometheus-stack.ts:
|
|
33
|
+
* ```yaml
|
|
34
|
+
* grafana:
|
|
35
|
+
* admin:
|
|
36
|
+
* existingSecret: "grafana-admin-credentials"
|
|
37
|
+
* userKey: "admin-user"
|
|
38
|
+
* passwordKey: "admin-password"
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* Manual Setup Required:
|
|
42
|
+
* 1. Create source secret in application-secrets namespace:
|
|
43
|
+
* ```bash
|
|
44
|
+
* kubectl create secret generic grafana-admin -n application-secrets \
|
|
45
|
+
* --from-literal=admin-user=admin \
|
|
46
|
+
* --from-literal=admin-password='YourSecurePassword123!'
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* 2. Create ClusterSecretStore (if not exists):
|
|
50
|
+
* See: documentation/sources/deployments/monitoring/how-to/setup-grafana-password.md
|
|
51
|
+
*
|
|
52
|
+
* 3. Deploy monitoring stack (this ExternalSecret will sync the secret)
|
|
53
|
+
*/
|
|
54
|
+
class GrafanaPasswordSecret extends constructs_1.Construct {
|
|
55
|
+
constructor(scope, id, props) {
|
|
56
|
+
super(scope, id);
|
|
57
|
+
const { namespace } = props;
|
|
58
|
+
// Create ExternalSecret to replicate Grafana credentials from application-secrets
|
|
59
|
+
// Wave 1: Credentials must exist before Grafana starts (Wave 2)
|
|
60
|
+
this.externalSecret = new external_secrets_io_1.ExternalSecret(this, 'external-secret', {
|
|
61
|
+
metadata: {
|
|
62
|
+
name: 'grafana-admin-credentials-es',
|
|
63
|
+
namespace,
|
|
64
|
+
labels: {
|
|
65
|
+
'app.kubernetes.io/name': 'grafana',
|
|
66
|
+
'app.kubernetes.io/component': 'credentials',
|
|
67
|
+
'app.kubernetes.io/managed-by': 'external-secrets',
|
|
68
|
+
},
|
|
69
|
+
annotations: {
|
|
70
|
+
'argocd.argoproj.io/sync-wave': '1',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
spec: {
|
|
74
|
+
// Sync every hour to detect password rotation
|
|
75
|
+
refreshInterval: '1h',
|
|
76
|
+
// Reference to ClusterSecretStore (application-secrets → monitoring)
|
|
77
|
+
secretStoreRef: {
|
|
78
|
+
name: 'monitoring-app-secrets-store',
|
|
79
|
+
kind: external_secrets_io_1.ExternalSecretSpecSecretStoreRefKind.CLUSTER_SECRET_STORE,
|
|
80
|
+
},
|
|
81
|
+
// Target secret name that Grafana will use
|
|
82
|
+
target: {
|
|
83
|
+
name: 'grafana-admin-credentials',
|
|
84
|
+
creationPolicy: external_secrets_io_1.ExternalSecretSpecTargetCreationPolicy.OWNER,
|
|
85
|
+
},
|
|
86
|
+
// Copy all data from source secret (admin-user, admin-password)
|
|
87
|
+
dataFrom: [
|
|
88
|
+
{
|
|
89
|
+
extract: {
|
|
90
|
+
key: 'grafana-admin',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.GrafanaPasswordSecret = GrafanaPasswordSecret;
|
|
99
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JhZmFuYS1wYXNzd29yZC1zZWNyZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uc3RydWN0cy9ncmFmYW5hLXBhc3N3b3JkLXNlY3JldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwyQ0FBdUM7QUFDdkMsd0VBSXdDO0FBTXhDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQStDRztBQUNILE1BQWEscUJBQXNCLFNBQVEsc0JBQVM7SUFHbEQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFpQztRQUN6RSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxLQUFLLENBQUM7UUFFNUIsa0ZBQWtGO1FBQ2xGLGdFQUFnRTtRQUNoRSxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksb0NBQWMsQ0FBQyxJQUFJLEVBQUUsaUJBQWlCLEVBQUU7WUFDaEUsUUFBUSxFQUFFO2dCQUNSLElBQUksRUFBRSw4QkFBOEI7Z0JBQ3BDLFNBQVM7Z0JBQ1QsTUFBTSxFQUFFO29CQUNOLHdCQUF3QixFQUFFLFNBQVM7b0JBQ25DLDZCQUE2QixFQUFFLGFBQWE7b0JBQzVDLDhCQUE4QixFQUFFLGtCQUFrQjtpQkFDbkQ7Z0JBQ0QsV0FBVyxFQUFFO29CQUNYLDhCQUE4QixFQUFFLEdBQUc7aUJBQ3BDO2FBQ0Y7WUFDRCxJQUFJLEVBQUU7Z0JBQ0osOENBQThDO2dCQUM5QyxlQUFlLEVBQUUsSUFBSTtnQkFFckIscUVBQXFFO2dCQUNyRSxjQUFjLEVBQUU7b0JBQ2QsSUFBSSxFQUFFLDhCQUE4QjtvQkFDcEMsSUFBSSxFQUFFLDBEQUFvQyxDQUFDLG9CQUFvQjtpQkFDaEU7Z0JBRUQsMkNBQTJDO2dCQUMzQyxNQUFNLEVBQUU7b0JBQ04sSUFBSSxFQUFFLDJCQUEyQjtvQkFDakMsY0FBYyxFQUFFLDREQUFzQyxDQUFDLEtBQUs7aUJBQzdEO2dCQUVELGdFQUFnRTtnQkFDaEUsUUFBUSxFQUFFO29CQUNSO3dCQUNFLE9BQU8sRUFBRTs0QkFDUCxHQUFHLEVBQUUsZUFBZTt5QkFDckI7cUJBQ0Y7aUJBQ0Y7YUFDRjtTQUNGLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQWxERCxzREFrREMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7XG4gIEV4dGVybmFsU2VjcmV0LFxuICBFeHRlcm5hbFNlY3JldFNwZWNUYXJnZXRDcmVhdGlvblBvbGljeSxcbiAgRXh0ZXJuYWxTZWNyZXRTcGVjU2VjcmV0U3RvcmVSZWZLaW5kLFxufSBmcm9tICcuLi9pbXBvcnRzL2V4dGVybmFsLXNlY3JldHMuaW8nO1xuXG5leHBvcnQgaW50ZXJmYWNlIEdyYWZhbmFQYXNzd29yZFNlY3JldFByb3BzIHtcbiAgcmVhZG9ubHkgbmFtZXNwYWNlOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBFeHRlcm5hbFNlY3JldCBmb3Igc3RhYmxlIEdyYWZhbmEgYWRtaW4gY3JlZGVudGlhbHMuXG4gKlxuICogVGhpcyBjb25zdHJ1Y3QgY3JlYXRlcyBhbiBFeHRlcm5hbFNlY3JldCB0aGF0IHJlcGxpY2F0ZXMgdGhlIEdyYWZhbmEgYWRtaW4gcGFzc3dvcmRcbiAqIGZyb20gdGhlIGFwcGxpY2F0aW9uLXNlY3JldHMgbmFtZXNwYWNlIHRvIHRoZSBtb25pdG9yaW5nIG5hbWVzcGFjZSwgZm9sbG93aW5nIHRoZVxuICogY2VudHJhbGl6ZWQgc2VjcmV0IG1hbmFnZW1lbnQgcGF0dGVybi5cbiAqXG4gKiBQcmVyZXF1aXNpdGVzOlxuICogLSBFeHRlcm5hbCBTZWNyZXRzIE9wZXJhdG9yIGluc3RhbGxlZFxuICogLSBDbHVzdGVyU2VjcmV0U3RvcmUgJ21vbml0b3JpbmctYXBwLXNlY3JldHMtc3RvcmUnIGV4aXN0cyAocG9pbnRzIHRvIGFwcGxpY2F0aW9uLXNlY3JldHMpXG4gKiAtIFNlY3JldCAnZ3JhZmFuYS1hZG1pbicgZXhpc3RzIGluIGFwcGxpY2F0aW9uLXNlY3JldHMgbmFtZXNwYWNlIHdpdGgga2V5czpcbiAqICAgLSBhZG1pbi11c2VyXG4gKiAgIC0gYWRtaW4tcGFzc3dvcmRcbiAqXG4gKiBTZWN1cml0eSBNb2RlbDpcbiAqIC0gU291cmNlIHNlY3JldCBzdG9yZWQgaW4gY2VudHJhbGl6ZWQgYXBwbGljYXRpb24tc2VjcmV0cyBuYW1lc3BhY2VcbiAqIC0gRXh0ZXJuYWxTZWNyZXQgQ1IgKHRoaXMpIGNvbW1pdHRlZCB0byBnaXQgKEdpdE9wcy1zYWZlLCBubyBwYXNzd29yZCBpbiBnaXQpXG4gKiAtIEVTTyBhdXRvbWF0aWNhbGx5IHJlcGxpY2F0ZXMgc2VjcmV0IHRvIG1vbml0b3JpbmcgbmFtZXNwYWNlXG4gKiAtIFBhc3N3b3JkIHBlcnNpc3RzIGFjcm9zcyBIZWxtIHVwZ3JhZGVzIChubyBhdXRvLXJlZ2VuZXJhdGlvbilcbiAqXG4gKiBCZW5lZml0czpcbiAqIC0gQ2VudHJhbGl6ZWQgc2VjcmV0IG1hbmFnZW1lbnQgKGFsbCBhcHAgc2VjcmV0cyBpbiBhcHBsaWNhdGlvbi1zZWNyZXRzIG5hbWVzcGFjZSlcbiAqIC0gR2l0T3BzLXNhZmUgKEV4dGVybmFsU2VjcmV0IGluIGdpdCwgYWN0dWFsIHBhc3N3b3JkIG5vdCBpbiBnaXQpXG4gKiAtIFBhc3N3b3JkIHJvdGF0aW9uICh1cGRhdGUgc291cmNlIOKGkiBhdXRvLXN5bmMgdG8gbW9uaXRvcmluZylcbiAqIC0gRm9sbG93cyBHaXRMYWIgQkRBIHNlY3VyaXR5IG1vZGVsIChzZWUgZG9jdW1lbnRhdGlvbi9zb3VyY2VzL2RlcGxveW1lbnRzL2dpdGxhYmJkYS9leHBsYW5hdGlvbi9zZWN1cml0eS1tb2RlbC5tZClcbiAqXG4gKiBVc2FnZSBpbiBwcm9tZXRoZXVzLXN0YWNrLnRzOlxuICogYGBgeWFtbFxuICogZ3JhZmFuYTpcbiAqICAgYWRtaW46XG4gKiAgICAgZXhpc3RpbmdTZWNyZXQ6IFwiZ3JhZmFuYS1hZG1pbi1jcmVkZW50aWFsc1wiXG4gKiAgICAgdXNlcktleTogXCJhZG1pbi11c2VyXCJcbiAqICAgICBwYXNzd29yZEtleTogXCJhZG1pbi1wYXNzd29yZFwiXG4gKiBgYGBcbiAqXG4gKiBNYW51YWwgU2V0dXAgUmVxdWlyZWQ6XG4gKiAxLiBDcmVhdGUgc291cmNlIHNlY3JldCBpbiBhcHBsaWNhdGlvbi1zZWNyZXRzIG5hbWVzcGFjZTpcbiAqICAgIGBgYGJhc2hcbiAqICAgIGt1YmVjdGwgY3JlYXRlIHNlY3JldCBnZW5lcmljIGdyYWZhbmEtYWRtaW4gLW4gYXBwbGljYXRpb24tc2VjcmV0cyBcXFxuICogICAgICAtLWZyb20tbGl0ZXJhbD1hZG1pbi11c2VyPWFkbWluIFxcXG4gKiAgICAgIC0tZnJvbS1saXRlcmFsPWFkbWluLXBhc3N3b3JkPSdZb3VyU2VjdXJlUGFzc3dvcmQxMjMhJ1xuICogICAgYGBgXG4gKlxuICogMi4gQ3JlYXRlIENsdXN0ZXJTZWNyZXRTdG9yZSAoaWYgbm90IGV4aXN0cyk6XG4gKiAgICBTZWU6IGRvY3VtZW50YXRpb24vc291cmNlcy9kZXBsb3ltZW50cy9tb25pdG9yaW5nL2hvdy10by9zZXR1cC1ncmFmYW5hLXBhc3N3b3JkLm1kXG4gKlxuICogMy4gRGVwbG95IG1vbml0b3Jpbmcgc3RhY2sgKHRoaXMgRXh0ZXJuYWxTZWNyZXQgd2lsbCBzeW5jIHRoZSBzZWNyZXQpXG4gKi9cbmV4cG9ydCBjbGFzcyBHcmFmYW5hUGFzc3dvcmRTZWNyZXQgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwdWJsaWMgcmVhZG9ubHkgZXh0ZXJuYWxTZWNyZXQ6IEV4dGVybmFsU2VjcmV0O1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBHcmFmYW5hUGFzc3dvcmRTZWNyZXRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCB7IG5hbWVzcGFjZSB9ID0gcHJvcHM7XG5cbiAgICAvLyBDcmVhdGUgRXh0ZXJuYWxTZWNyZXQgdG8gcmVwbGljYXRlIEdyYWZhbmEgY3JlZGVudGlhbHMgZnJvbSBhcHBsaWNhdGlvbi1zZWNyZXRzXG4gICAgLy8gV2F2ZSAxOiBDcmVkZW50aWFscyBtdXN0IGV4aXN0IGJlZm9yZSBHcmFmYW5hIHN0YXJ0cyAoV2F2ZSAyKVxuICAgIHRoaXMuZXh0ZXJuYWxTZWNyZXQgPSBuZXcgRXh0ZXJuYWxTZWNyZXQodGhpcywgJ2V4dGVybmFsLXNlY3JldCcsIHtcbiAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgIG5hbWU6ICdncmFmYW5hLWFkbWluLWNyZWRlbnRpYWxzLWVzJyxcbiAgICAgICAgbmFtZXNwYWNlLFxuICAgICAgICBsYWJlbHM6IHtcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vbmFtZSc6ICdncmFmYW5hJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50JzogJ2NyZWRlbnRpYWxzJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vbWFuYWdlZC1ieSc6ICdleHRlcm5hbC1zZWNyZXRzJyxcbiAgICAgICAgfSxcbiAgICAgICAgYW5ub3RhdGlvbnM6IHtcbiAgICAgICAgICAnYXJnb2NkLmFyZ29wcm9qLmlvL3N5bmMtd2F2ZSc6ICcxJyxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBzcGVjOiB7XG4gICAgICAgIC8vIFN5bmMgZXZlcnkgaG91ciB0byBkZXRlY3QgcGFzc3dvcmQgcm90YXRpb25cbiAgICAgICAgcmVmcmVzaEludGVydmFsOiAnMWgnLFxuXG4gICAgICAgIC8vIFJlZmVyZW5jZSB0byBDbHVzdGVyU2VjcmV0U3RvcmUgKGFwcGxpY2F0aW9uLXNlY3JldHMg4oaSIG1vbml0b3JpbmcpXG4gICAgICAgIHNlY3JldFN0b3JlUmVmOiB7XG4gICAgICAgICAgbmFtZTogJ21vbml0b3JpbmctYXBwLXNlY3JldHMtc3RvcmUnLFxuICAgICAgICAgIGtpbmQ6IEV4dGVybmFsU2VjcmV0U3BlY1NlY3JldFN0b3JlUmVmS2luZC5DTFVTVEVSX1NFQ1JFVF9TVE9SRSxcbiAgICAgICAgfSxcblxuICAgICAgICAvLyBUYXJnZXQgc2VjcmV0IG5hbWUgdGhhdCBHcmFmYW5hIHdpbGwgdXNlXG4gICAgICAgIHRhcmdldDoge1xuICAgICAgICAgIG5hbWU6ICdncmFmYW5hLWFkbWluLWNyZWRlbnRpYWxzJyxcbiAgICAgICAgICBjcmVhdGlvblBvbGljeTogRXh0ZXJuYWxTZWNyZXRTcGVjVGFyZ2V0Q3JlYXRpb25Qb2xpY3kuT1dORVIsXG4gICAgICAgIH0sXG5cbiAgICAgICAgLy8gQ29weSBhbGwgZGF0YSBmcm9tIHNvdXJjZSBzZWNyZXQgKGFkbWluLXVzZXIsIGFkbWluLXBhc3N3b3JkKVxuICAgICAgICBkYXRhRnJvbTogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGV4dHJhY3Q6IHtcbiAgICAgICAgICAgICAga2V5OiAnZ3JhZmFuYS1hZG1pbicsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgIH0pO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import { MonitoringConfig } from '../types';
|
|
3
|
+
export interface LokiS3BucketProps {
|
|
4
|
+
config: MonitoringConfig;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Creates Crossplane Bucket resources for Loki log storage.
|
|
8
|
+
*
|
|
9
|
+
* This construct generates:
|
|
10
|
+
* - S3 Bucket (via Crossplane Upbound provider-aws-s3)
|
|
11
|
+
* - BucketVersioning (for recovery of accidentally deleted logs)
|
|
12
|
+
* - BucketLifecycleConfiguration (90-day retention)
|
|
13
|
+
*
|
|
14
|
+
* Prerequisites:
|
|
15
|
+
* - Crossplane operator installed
|
|
16
|
+
* - Upbound provider-aws-s3 installed
|
|
17
|
+
* - ProviderConfig 'hetzner-s3' configured (points to Hetzner S3)
|
|
18
|
+
* - Hetzner S3 credentials secret exists in crossplane-system
|
|
19
|
+
*
|
|
20
|
+
* Sync Wave: 1 (external dependencies - must exist before pods access S3)
|
|
21
|
+
*/
|
|
22
|
+
export declare class LokiS3BucketConstruct extends Construct {
|
|
23
|
+
constructor(scope: Construct, id: string, props: LokiS3BucketProps);
|
|
24
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LokiS3BucketConstruct = void 0;
|
|
4
|
+
const cdk8s_1 = require("cdk8s");
|
|
5
|
+
const constructs_1 = require("constructs");
|
|
6
|
+
const s3_aws_upbound_io_1 = require("../imports/s3.aws.upbound.io");
|
|
7
|
+
/**
|
|
8
|
+
* Creates Crossplane Bucket resources for Loki log storage.
|
|
9
|
+
*
|
|
10
|
+
* This construct generates:
|
|
11
|
+
* - S3 Bucket (via Crossplane Upbound provider-aws-s3)
|
|
12
|
+
* - BucketVersioning (for recovery of accidentally deleted logs)
|
|
13
|
+
* - BucketLifecycleConfiguration (90-day retention)
|
|
14
|
+
*
|
|
15
|
+
* Prerequisites:
|
|
16
|
+
* - Crossplane operator installed
|
|
17
|
+
* - Upbound provider-aws-s3 installed
|
|
18
|
+
* - ProviderConfig 'hetzner-s3' configured (points to Hetzner S3)
|
|
19
|
+
* - Hetzner S3 credentials secret exists in crossplane-system
|
|
20
|
+
*
|
|
21
|
+
* Sync Wave: 1 (external dependencies - must exist before pods access S3)
|
|
22
|
+
*/
|
|
23
|
+
class LokiS3BucketConstruct extends constructs_1.Construct {
|
|
24
|
+
constructor(scope, id, props) {
|
|
25
|
+
super(scope, id);
|
|
26
|
+
const { config } = props;
|
|
27
|
+
const bucketName = config.s3.buckets.loki;
|
|
28
|
+
const region = config.s3.region;
|
|
29
|
+
// Create Bucket
|
|
30
|
+
// Wave 1: External Dependencies - S3 bucket provisioned by Crossplane
|
|
31
|
+
// Note: Using ApiObject because cdk8s import limitations prevent importing Bucket type
|
|
32
|
+
new cdk8s_1.ApiObject(this, 'bucket', {
|
|
33
|
+
apiVersion: 's3.aws.upbound.io/v1beta2',
|
|
34
|
+
kind: 'Bucket',
|
|
35
|
+
metadata: {
|
|
36
|
+
name: bucketName,
|
|
37
|
+
namespace: 'crossplane-system',
|
|
38
|
+
labels: {
|
|
39
|
+
'app.kubernetes.io/name': 'loki',
|
|
40
|
+
'app.kubernetes.io/component': 'storage',
|
|
41
|
+
'app.kubernetes.io/managed-by': 'cdk8s',
|
|
42
|
+
'app.kubernetes.io/part-of': 'monitoring',
|
|
43
|
+
},
|
|
44
|
+
annotations: {
|
|
45
|
+
'argocd.argoproj.io/sync-wave': '1',
|
|
46
|
+
'crossplane.io/external-name': bucketName,
|
|
47
|
+
'description': 'Loki log storage (90-day retention)',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
spec: {
|
|
51
|
+
deletionPolicy: 'Delete',
|
|
52
|
+
managementPolicies: [
|
|
53
|
+
'Observe',
|
|
54
|
+
'Create',
|
|
55
|
+
'Delete',
|
|
56
|
+
// Skip Update to avoid tagging operations (not supported by Hetzner S3)
|
|
57
|
+
],
|
|
58
|
+
forProvider: {
|
|
59
|
+
region: region, // Production region (endpoint determines actual location)
|
|
60
|
+
},
|
|
61
|
+
providerConfigRef: {
|
|
62
|
+
name: 'hetzner-s3',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
// Create BucketVersioning
|
|
67
|
+
// Enable versioning for recovery of accidentally deleted logs
|
|
68
|
+
// Note: Using ApiObject because cdk8s import limitations prevent importing BucketVersioning type
|
|
69
|
+
new cdk8s_1.ApiObject(this, 'versioning', {
|
|
70
|
+
apiVersion: 's3.aws.upbound.io/v1beta2',
|
|
71
|
+
kind: 'BucketVersioning',
|
|
72
|
+
metadata: {
|
|
73
|
+
name: 'loki-logs-versioning',
|
|
74
|
+
namespace: 'crossplane-system',
|
|
75
|
+
labels: {
|
|
76
|
+
'app.kubernetes.io/name': 'loki',
|
|
77
|
+
'app.kubernetes.io/component': 'storage',
|
|
78
|
+
'app.kubernetes.io/managed-by': 'cdk8s',
|
|
79
|
+
'app.kubernetes.io/part-of': 'monitoring',
|
|
80
|
+
},
|
|
81
|
+
annotations: {
|
|
82
|
+
'argocd.argoproj.io/sync-wave': '1',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
spec: {
|
|
86
|
+
forProvider: {
|
|
87
|
+
region: region, // Production region (same as bucket)
|
|
88
|
+
bucketRef: {
|
|
89
|
+
name: bucketName,
|
|
90
|
+
},
|
|
91
|
+
versioningConfiguration: {
|
|
92
|
+
status: 'Enabled',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
providerConfigRef: {
|
|
96
|
+
name: 'hetzner-s3',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
// Create BucketLifecycleConfiguration
|
|
101
|
+
// Lifecycle policy: automatically delete logs older than 90 days
|
|
102
|
+
new s3_aws_upbound_io_1.BucketLifecycleConfiguration(this, 'lifecycle', {
|
|
103
|
+
metadata: {
|
|
104
|
+
name: 'loki-logs-lifecycle',
|
|
105
|
+
namespace: 'crossplane-system',
|
|
106
|
+
labels: {
|
|
107
|
+
'app.kubernetes.io/name': 'loki',
|
|
108
|
+
'app.kubernetes.io/component': 'storage',
|
|
109
|
+
'app.kubernetes.io/managed-by': 'cdk8s',
|
|
110
|
+
'app.kubernetes.io/part-of': 'monitoring',
|
|
111
|
+
},
|
|
112
|
+
annotations: {
|
|
113
|
+
'argocd.argoproj.io/sync-wave': '1',
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
spec: {
|
|
117
|
+
managementPolicies: [
|
|
118
|
+
s3_aws_upbound_io_1.BucketLifecycleConfigurationSpecManagementPolicies.OBSERVE,
|
|
119
|
+
s3_aws_upbound_io_1.BucketLifecycleConfigurationSpecManagementPolicies.CREATE,
|
|
120
|
+
s3_aws_upbound_io_1.BucketLifecycleConfigurationSpecManagementPolicies.DELETE,
|
|
121
|
+
],
|
|
122
|
+
forProvider: {
|
|
123
|
+
region: region, // Production region (same as bucket)
|
|
124
|
+
bucketRef: {
|
|
125
|
+
name: bucketName,
|
|
126
|
+
},
|
|
127
|
+
rule: [
|
|
128
|
+
{
|
|
129
|
+
id: 'delete-old-logs',
|
|
130
|
+
status: 'Enabled',
|
|
131
|
+
expiration: [
|
|
132
|
+
{
|
|
133
|
+
days: 90, // 90-day retention (matches 31d Loki retention + buffer)
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
providerConfigRef: {
|
|
140
|
+
name: 'hetzner-s3',
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.LokiS3BucketConstruct = LokiS3BucketConstruct;
|
|
147
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9raS1zMy1idWNrZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uc3RydWN0cy9sb2tpLXMzLWJ1Y2tldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxpQ0FBa0M7QUFDbEMsMkNBQXVDO0FBQ3ZDLG9FQUFnSTtBQU9oSTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxNQUFhLHFCQUFzQixTQUFRLHNCQUFTO0lBQ2xELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBd0I7UUFDaEUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztRQUMxQyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQztRQUVoQyxnQkFBZ0I7UUFDaEIsc0VBQXNFO1FBQ3RFLHVGQUF1RjtRQUN2RixJQUFJLGlCQUFTLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRTtZQUM1QixVQUFVLEVBQUUsMkJBQTJCO1lBQ3ZDLElBQUksRUFBRSxRQUFRO1lBQ2QsUUFBUSxFQUFFO2dCQUNSLElBQUksRUFBRSxVQUFVO2dCQUNoQixTQUFTLEVBQUUsbUJBQW1CO2dCQUM5QixNQUFNLEVBQUU7b0JBQ04sd0JBQXdCLEVBQUUsTUFBTTtvQkFDaEMsNkJBQTZCLEVBQUUsU0FBUztvQkFDeEMsOEJBQThCLEVBQUUsT0FBTztvQkFDdkMsMkJBQTJCLEVBQUUsWUFBWTtpQkFDMUM7Z0JBQ0QsV0FBVyxFQUFFO29CQUNYLDhCQUE4QixFQUFFLEdBQUc7b0JBQ25DLDZCQUE2QixFQUFFLFVBQVU7b0JBQ3pDLGFBQWEsRUFBRSxxQ0FBcUM7aUJBQ3JEO2FBQ0Y7WUFDRCxJQUFJLEVBQUU7Z0JBQ0osY0FBYyxFQUFFLFFBQVE7Z0JBQ3hCLGtCQUFrQixFQUFFO29CQUNsQixTQUFTO29CQUNULFFBQVE7b0JBQ1IsUUFBUTtvQkFDUix3RUFBd0U7aUJBQ3pFO2dCQUNELFdBQVcsRUFBRTtvQkFDWCxNQUFNLEVBQUUsTUFBTSxFQUFFLDBEQUEwRDtpQkFDM0U7Z0JBQ0QsaUJBQWlCLEVBQUU7b0JBQ2pCLElBQUksRUFBRSxZQUFZO2lCQUNuQjthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsMEJBQTBCO1FBQzFCLDhEQUE4RDtRQUM5RCxpR0FBaUc7UUFDakcsSUFBSSxpQkFBUyxDQUFDLElBQUksRUFBRSxZQUFZLEVBQUU7WUFDaEMsVUFBVSxFQUFFLDJCQUEyQjtZQUN2QyxJQUFJLEVBQUUsa0JBQWtCO1lBQ3hCLFFBQVEsRUFBRTtnQkFDUixJQUFJLEVBQUUsc0JBQXNCO2dCQUM1QixTQUFTLEVBQUUsbUJBQW1CO2dCQUM5QixNQUFNLEVBQUU7b0JBQ04sd0JBQXdCLEVBQUUsTUFBTTtvQkFDaEMsNkJBQTZCLEVBQUUsU0FBUztvQkFDeEMsOEJBQThCLEVBQUUsT0FBTztvQkFDdkMsMkJBQTJCLEVBQUUsWUFBWTtpQkFDMUM7Z0JBQ0QsV0FBVyxFQUFFO29CQUNYLDhCQUE4QixFQUFFLEdBQUc7aUJBQ3BDO2FBQ0Y7WUFDRCxJQUFJLEVBQUU7Z0JBQ0osV0FBVyxFQUFFO29CQUNYLE1BQU0sRUFBRSxNQUFNLEVBQUUscUNBQXFDO29CQUNyRCxTQUFTLEVBQUU7d0JBQ1QsSUFBSSxFQUFFLFVBQVU7cUJBQ2pCO29CQUNELHVCQUF1QixFQUFFO3dCQUN2QixNQUFNLEVBQUUsU0FBUztxQkFDbEI7aUJBQ0Y7Z0JBQ0QsaUJBQWlCLEVBQUU7b0JBQ2pCLElBQUksRUFBRSxZQUFZO2lCQUNuQjthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsc0NBQXNDO1FBQ3RDLGlFQUFpRTtRQUNqRSxJQUFJLGdEQUE0QixDQUFDLElBQUksRUFBRSxXQUFXLEVBQUU7WUFDbEQsUUFBUSxFQUFFO2dCQUNSLElBQUksRUFBRSxxQkFBcUI7Z0JBQzNCLFNBQVMsRUFBRSxtQkFBbUI7Z0JBQzlCLE1BQU0sRUFBRTtvQkFDTix3QkFBd0IsRUFBRSxNQUFNO29CQUNoQyw2QkFBNkIsRUFBRSxTQUFTO29CQUN4Qyw4QkFBOEIsRUFBRSxPQUFPO29CQUN2QywyQkFBMkIsRUFBRSxZQUFZO2lCQUMxQztnQkFDRCxXQUFXLEVBQUU7b0JBQ1gsOEJBQThCLEVBQUUsR0FBRztpQkFDcEM7YUFDRjtZQUNELElBQUksRUFBRTtnQkFDSixrQkFBa0IsRUFBRTtvQkFDbEIsc0VBQWtELENBQUMsT0FBTztvQkFDMUQsc0VBQWtELENBQUMsTUFBTTtvQkFDekQsc0VBQWtELENBQUMsTUFBTTtpQkFDMUQ7Z0JBQ0QsV0FBVyxFQUFFO29CQUNYLE1BQU0sRUFBRSxNQUFNLEVBQUUscUNBQXFDO29CQUNyRCxTQUFTLEVBQUU7d0JBQ1QsSUFBSSxFQUFFLFVBQVU7cUJBQ2pCO29CQUNELElBQUksRUFBRTt3QkFDSjs0QkFDRSxFQUFFLEVBQUUsaUJBQWlCOzRCQUNyQixNQUFNLEVBQUUsU0FBUzs0QkFDakIsVUFBVSxFQUFFO2dDQUNWO29DQUNFLElBQUksRUFBRSxFQUFFLEVBQUUseURBQXlEO2lDQUNwRTs2QkFDRjt5QkFDRjtxQkFDRjtpQkFDRjtnQkFDRCxpQkFBaUIsRUFBRTtvQkFDakIsSUFBSSxFQUFFLFlBQVk7aUJBQ25CO2FBQ0Y7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUE5SEQsc0RBOEhDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQXBpT2JqZWN0IH0gZnJvbSAnY2RrOHMnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBCdWNrZXRMaWZlY3ljbGVDb25maWd1cmF0aW9uLCBCdWNrZXRMaWZlY3ljbGVDb25maWd1cmF0aW9uU3BlY01hbmFnZW1lbnRQb2xpY2llcyB9IGZyb20gJy4uL2ltcG9ydHMvczMuYXdzLnVwYm91bmQuaW8nO1xuaW1wb3J0IHsgTW9uaXRvcmluZ0NvbmZpZyB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGludGVyZmFjZSBMb2tpUzNCdWNrZXRQcm9wcyB7XG4gIGNvbmZpZzogTW9uaXRvcmluZ0NvbmZpZztcbn1cblxuLyoqXG4gKiBDcmVhdGVzIENyb3NzcGxhbmUgQnVja2V0IHJlc291cmNlcyBmb3IgTG9raSBsb2cgc3RvcmFnZS5cbiAqXG4gKiBUaGlzIGNvbnN0cnVjdCBnZW5lcmF0ZXM6XG4gKiAtIFMzIEJ1Y2tldCAodmlhIENyb3NzcGxhbmUgVXBib3VuZCBwcm92aWRlci1hd3MtczMpXG4gKiAtIEJ1Y2tldFZlcnNpb25pbmcgKGZvciByZWNvdmVyeSBvZiBhY2NpZGVudGFsbHkgZGVsZXRlZCBsb2dzKVxuICogLSBCdWNrZXRMaWZlY3ljbGVDb25maWd1cmF0aW9uICg5MC1kYXkgcmV0ZW50aW9uKVxuICpcbiAqIFByZXJlcXVpc2l0ZXM6XG4gKiAtIENyb3NzcGxhbmUgb3BlcmF0b3IgaW5zdGFsbGVkXG4gKiAtIFVwYm91bmQgcHJvdmlkZXItYXdzLXMzIGluc3RhbGxlZFxuICogLSBQcm92aWRlckNvbmZpZyAnaGV0em5lci1zMycgY29uZmlndXJlZCAocG9pbnRzIHRvIEhldHpuZXIgUzMpXG4gKiAtIEhldHpuZXIgUzMgY3JlZGVudGlhbHMgc2VjcmV0IGV4aXN0cyBpbiBjcm9zc3BsYW5lLXN5c3RlbVxuICpcbiAqIFN5bmMgV2F2ZTogMSAoZXh0ZXJuYWwgZGVwZW5kZW5jaWVzIC0gbXVzdCBleGlzdCBiZWZvcmUgcG9kcyBhY2Nlc3MgUzMpXG4gKi9cbmV4cG9ydCBjbGFzcyBMb2tpUzNCdWNrZXRDb25zdHJ1Y3QgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogTG9raVMzQnVja2V0UHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3QgeyBjb25maWcgfSA9IHByb3BzO1xuICAgIGNvbnN0IGJ1Y2tldE5hbWUgPSBjb25maWcuczMuYnVja2V0cy5sb2tpO1xuICAgIGNvbnN0IHJlZ2lvbiA9IGNvbmZpZy5zMy5yZWdpb247XG5cbiAgICAvLyBDcmVhdGUgQnVja2V0XG4gICAgLy8gV2F2ZSAxOiBFeHRlcm5hbCBEZXBlbmRlbmNpZXMgLSBTMyBidWNrZXQgcHJvdmlzaW9uZWQgYnkgQ3Jvc3NwbGFuZVxuICAgIC8vIE5vdGU6IFVzaW5nIEFwaU9iamVjdCBiZWNhdXNlIGNkazhzIGltcG9ydCBsaW1pdGF0aW9ucyBwcmV2ZW50IGltcG9ydGluZyBCdWNrZXQgdHlwZVxuICAgIG5ldyBBcGlPYmplY3QodGhpcywgJ2J1Y2tldCcsIHtcbiAgICAgIGFwaVZlcnNpb246ICdzMy5hd3MudXBib3VuZC5pby92MWJldGEyJyxcbiAgICAgIGtpbmQ6ICdCdWNrZXQnLFxuICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgbmFtZTogYnVja2V0TmFtZSxcbiAgICAgICAgbmFtZXNwYWNlOiAnY3Jvc3NwbGFuZS1zeXN0ZW0nLFxuICAgICAgICBsYWJlbHM6IHtcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vbmFtZSc6ICdsb2tpJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50JzogJ3N0b3JhZ2UnLFxuICAgICAgICAgICdhcHAua3ViZXJuZXRlcy5pby9tYW5hZ2VkLWJ5JzogJ2NkazhzJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vcGFydC1vZic6ICdtb25pdG9yaW5nJyxcbiAgICAgICAgfSxcbiAgICAgICAgYW5ub3RhdGlvbnM6IHtcbiAgICAgICAgICAnYXJnb2NkLmFyZ29wcm9qLmlvL3N5bmMtd2F2ZSc6ICcxJyxcbiAgICAgICAgICAnY3Jvc3NwbGFuZS5pby9leHRlcm5hbC1uYW1lJzogYnVja2V0TmFtZSxcbiAgICAgICAgICAnZGVzY3JpcHRpb24nOiAnTG9raSBsb2cgc3RvcmFnZSAoOTAtZGF5IHJldGVudGlvbiknLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIHNwZWM6IHtcbiAgICAgICAgZGVsZXRpb25Qb2xpY3k6ICdEZWxldGUnLFxuICAgICAgICBtYW5hZ2VtZW50UG9saWNpZXM6IFtcbiAgICAgICAgICAnT2JzZXJ2ZScsXG4gICAgICAgICAgJ0NyZWF0ZScsXG4gICAgICAgICAgJ0RlbGV0ZScsXG4gICAgICAgICAgLy8gU2tpcCBVcGRhdGUgdG8gYXZvaWQgdGFnZ2luZyBvcGVyYXRpb25zIChub3Qgc3VwcG9ydGVkIGJ5IEhldHpuZXIgUzMpXG4gICAgICAgIF0sXG4gICAgICAgIGZvclByb3ZpZGVyOiB7XG4gICAgICAgICAgcmVnaW9uOiByZWdpb24sIC8vIFByb2R1Y3Rpb24gcmVnaW9uIChlbmRwb2ludCBkZXRlcm1pbmVzIGFjdHVhbCBsb2NhdGlvbilcbiAgICAgICAgfSxcbiAgICAgICAgcHJvdmlkZXJDb25maWdSZWY6IHtcbiAgICAgICAgICBuYW1lOiAnaGV0em5lci1zMycsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gQ3JlYXRlIEJ1Y2tldFZlcnNpb25pbmdcbiAgICAvLyBFbmFibGUgdmVyc2lvbmluZyBmb3IgcmVjb3Zlcnkgb2YgYWNjaWRlbnRhbGx5IGRlbGV0ZWQgbG9nc1xuICAgIC8vIE5vdGU6IFVzaW5nIEFwaU9iamVjdCBiZWNhdXNlIGNkazhzIGltcG9ydCBsaW1pdGF0aW9ucyBwcmV2ZW50IGltcG9ydGluZyBCdWNrZXRWZXJzaW9uaW5nIHR5cGVcbiAgICBuZXcgQXBpT2JqZWN0KHRoaXMsICd2ZXJzaW9uaW5nJywge1xuICAgICAgYXBpVmVyc2lvbjogJ3MzLmF3cy51cGJvdW5kLmlvL3YxYmV0YTInLFxuICAgICAga2luZDogJ0J1Y2tldFZlcnNpb25pbmcnLFxuICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgbmFtZTogJ2xva2ktbG9ncy12ZXJzaW9uaW5nJyxcbiAgICAgICAgbmFtZXNwYWNlOiAnY3Jvc3NwbGFuZS1zeXN0ZW0nLFxuICAgICAgICBsYWJlbHM6IHtcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vbmFtZSc6ICdsb2tpJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50JzogJ3N0b3JhZ2UnLFxuICAgICAgICAgICdhcHAua3ViZXJuZXRlcy5pby9tYW5hZ2VkLWJ5JzogJ2NkazhzJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vcGFydC1vZic6ICdtb25pdG9yaW5nJyxcbiAgICAgICAgfSxcbiAgICAgICAgYW5ub3RhdGlvbnM6IHtcbiAgICAgICAgICAnYXJnb2NkLmFyZ29wcm9qLmlvL3N5bmMtd2F2ZSc6ICcxJyxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBzcGVjOiB7XG4gICAgICAgIGZvclByb3ZpZGVyOiB7XG4gICAgICAgICAgcmVnaW9uOiByZWdpb24sIC8vIFByb2R1Y3Rpb24gcmVnaW9uIChzYW1lIGFzIGJ1Y2tldClcbiAgICAgICAgICBidWNrZXRSZWY6IHtcbiAgICAgICAgICAgIG5hbWU6IGJ1Y2tldE5hbWUsXG4gICAgICAgICAgfSxcbiAgICAgICAgICB2ZXJzaW9uaW5nQ29uZmlndXJhdGlvbjoge1xuICAgICAgICAgICAgc3RhdHVzOiAnRW5hYmxlZCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgcHJvdmlkZXJDb25maWdSZWY6IHtcbiAgICAgICAgICBuYW1lOiAnaGV0em5lci1zMycsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gQ3JlYXRlIEJ1Y2tldExpZmVjeWNsZUNvbmZpZ3VyYXRpb25cbiAgICAvLyBMaWZlY3ljbGUgcG9saWN5OiBhdXRvbWF0aWNhbGx5IGRlbGV0ZSBsb2dzIG9sZGVyIHRoYW4gOTAgZGF5c1xuICAgIG5ldyBCdWNrZXRMaWZlY3ljbGVDb25maWd1cmF0aW9uKHRoaXMsICdsaWZlY3ljbGUnLCB7XG4gICAgICBtZXRhZGF0YToge1xuICAgICAgICBuYW1lOiAnbG9raS1sb2dzLWxpZmVjeWNsZScsXG4gICAgICAgIG5hbWVzcGFjZTogJ2Nyb3NzcGxhbmUtc3lzdGVtJyxcbiAgICAgICAgbGFiZWxzOiB7XG4gICAgICAgICAgJ2FwcC5rdWJlcm5ldGVzLmlvL25hbWUnOiAnbG9raScsXG4gICAgICAgICAgJ2FwcC5rdWJlcm5ldGVzLmlvL2NvbXBvbmVudCc6ICdzdG9yYWdlJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vbWFuYWdlZC1ieSc6ICdjZGs4cycsXG4gICAgICAgICAgJ2FwcC5rdWJlcm5ldGVzLmlvL3BhcnQtb2YnOiAnbW9uaXRvcmluZycsXG4gICAgICAgIH0sXG4gICAgICAgIGFubm90YXRpb25zOiB7XG4gICAgICAgICAgJ2FyZ29jZC5hcmdvcHJvai5pby9zeW5jLXdhdmUnOiAnMScsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgc3BlYzoge1xuICAgICAgICBtYW5hZ2VtZW50UG9saWNpZXM6IFtcbiAgICAgICAgICBCdWNrZXRMaWZlY3ljbGVDb25maWd1cmF0aW9uU3BlY01hbmFnZW1lbnRQb2xpY2llcy5PQlNFUlZFLFxuICAgICAgICAgIEJ1Y2tldExpZmVjeWNsZUNvbmZpZ3VyYXRpb25TcGVjTWFuYWdlbWVudFBvbGljaWVzLkNSRUFURSxcbiAgICAgICAgICBCdWNrZXRMaWZlY3ljbGVDb25maWd1cmF0aW9uU3BlY01hbmFnZW1lbnRQb2xpY2llcy5ERUxFVEUsXG4gICAgICAgIF0sXG4gICAgICAgIGZvclByb3ZpZGVyOiB7XG4gICAgICAgICAgcmVnaW9uOiByZWdpb24sIC8vIFByb2R1Y3Rpb24gcmVnaW9uIChzYW1lIGFzIGJ1Y2tldClcbiAgICAgICAgICBidWNrZXRSZWY6IHtcbiAgICAgICAgICAgIG5hbWU6IGJ1Y2tldE5hbWUsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBydWxlOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGlkOiAnZGVsZXRlLW9sZC1sb2dzJyxcbiAgICAgICAgICAgICAgc3RhdHVzOiAnRW5hYmxlZCcsXG4gICAgICAgICAgICAgIGV4cGlyYXRpb246IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBkYXlzOiA5MCwgLy8gOTAtZGF5IHJldGVudGlvbiAobWF0Y2hlcyAzMWQgTG9raSByZXRlbnRpb24gKyBidWZmZXIpXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgcHJvdmlkZXJDb25maWdSZWY6IHtcbiAgICAgICAgICBuYW1lOiAnaGV0em5lci1zMycsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import { MonitoringConfig } from '../types';
|
|
3
|
+
export interface LokiS3CredentialsProps {
|
|
4
|
+
namespace: string;
|
|
5
|
+
config: MonitoringConfig;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Creates ExternalSecret for Loki S3 credentials.
|
|
9
|
+
*
|
|
10
|
+
* This construct replicates Hetzner S3 credentials from crossplane-system
|
|
11
|
+
* namespace to monitoring namespace for Loki's object storage.
|
|
12
|
+
*
|
|
13
|
+
* Prerequisites:
|
|
14
|
+
* - External Secrets Operator installed
|
|
15
|
+
* - ClusterSecretStore 'hetzner-s3-cluster-store' exists (points to crossplane-system)
|
|
16
|
+
* - Secret 'hetzner-s3-creds-standard' exists in crossplane-system namespace
|
|
17
|
+
*
|
|
18
|
+
* Generated Secret:
|
|
19
|
+
* - Name: loki-s3-credentials
|
|
20
|
+
* - Keys: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
|
|
21
|
+
*
|
|
22
|
+
* Sync Wave: 1 (external dependencies - must exist before Loki starts)
|
|
23
|
+
*/
|
|
24
|
+
export declare class LokiS3CredentialsConstruct extends Construct {
|
|
25
|
+
readonly secretName = "loki-s3-credentials";
|
|
26
|
+
constructor(scope: Construct, id: string, props: LokiS3CredentialsProps);
|
|
27
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LokiS3CredentialsConstruct = void 0;
|
|
4
|
+
const constructs_1 = require("constructs");
|
|
5
|
+
const external_secrets_io_1 = require("../imports/external-secrets.io");
|
|
6
|
+
/**
|
|
7
|
+
* Creates ExternalSecret for Loki S3 credentials.
|
|
8
|
+
*
|
|
9
|
+
* This construct replicates Hetzner S3 credentials from crossplane-system
|
|
10
|
+
* namespace to monitoring namespace for Loki's object storage.
|
|
11
|
+
*
|
|
12
|
+
* Prerequisites:
|
|
13
|
+
* - External Secrets Operator installed
|
|
14
|
+
* - ClusterSecretStore 'hetzner-s3-cluster-store' exists (points to crossplane-system)
|
|
15
|
+
* - Secret 'hetzner-s3-creds-standard' exists in crossplane-system namespace
|
|
16
|
+
*
|
|
17
|
+
* Generated Secret:
|
|
18
|
+
* - Name: loki-s3-credentials
|
|
19
|
+
* - Keys: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
|
|
20
|
+
*
|
|
21
|
+
* Sync Wave: 1 (external dependencies - must exist before Loki starts)
|
|
22
|
+
*/
|
|
23
|
+
class LokiS3CredentialsConstruct extends constructs_1.Construct {
|
|
24
|
+
constructor(scope, id, props) {
|
|
25
|
+
super(scope, id);
|
|
26
|
+
this.secretName = 'loki-s3-credentials';
|
|
27
|
+
const { namespace } = props;
|
|
28
|
+
// Create ExternalSecret that replicates S3 credentials
|
|
29
|
+
// Wave 1: External Dependencies - credentials must exist before Loki components
|
|
30
|
+
new external_secrets_io_1.ExternalSecret(this, 'loki-s3-external-secret', {
|
|
31
|
+
metadata: {
|
|
32
|
+
name: 'loki-s3-credentials-es',
|
|
33
|
+
namespace: namespace,
|
|
34
|
+
labels: {
|
|
35
|
+
'app.kubernetes.io/name': 'loki',
|
|
36
|
+
'app.kubernetes.io/component': 's3-credentials',
|
|
37
|
+
'app.kubernetes.io/managed-by': 'cdk8s',
|
|
38
|
+
'app.kubernetes.io/part-of': 'monitoring',
|
|
39
|
+
},
|
|
40
|
+
annotations: {
|
|
41
|
+
'argocd.argoproj.io/sync-wave': '1',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
spec: {
|
|
45
|
+
// Refresh credentials every hour (automatic rotation support)
|
|
46
|
+
// Use full format to match Kubernetes normalization and avoid ArgoCD drift
|
|
47
|
+
refreshInterval: '1h0m0s',
|
|
48
|
+
// Use existing ClusterSecretStore for Hetzner S3 (infrastructure-level secrets)
|
|
49
|
+
secretStoreRef: {
|
|
50
|
+
name: 'hetzner-s3-cluster-store',
|
|
51
|
+
kind: external_secrets_io_1.ExternalSecretSpecSecretStoreRefKind.CLUSTER_SECRET_STORE,
|
|
52
|
+
},
|
|
53
|
+
// Target secret that Loki will consume via extraEnvFrom
|
|
54
|
+
target: {
|
|
55
|
+
name: this.secretName,
|
|
56
|
+
creationPolicy: external_secrets_io_1.ExternalSecretSpecTargetCreationPolicy.OWNER,
|
|
57
|
+
},
|
|
58
|
+
// Fetch S3 credentials from crossplane-system/hetzner-s3-creds-standard
|
|
59
|
+
dataFrom: [
|
|
60
|
+
{
|
|
61
|
+
extract: {
|
|
62
|
+
key: 'hetzner-s3-creds-standard',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.LokiS3CredentialsConstruct = LokiS3CredentialsConstruct;
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9raS1zMy1jcmVkZW50aWFscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb25zdHJ1Y3RzL2xva2ktczMtY3JlZGVudGlhbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMkNBQXVDO0FBQ3ZDLHdFQUl3QztBQVF4Qzs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILE1BQWEsMEJBQTJCLFNBQVEsc0JBQVM7SUFHdkQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUE2QjtRQUNyRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBSEgsZUFBVSxHQUFHLHFCQUFxQixDQUFDO1FBS2pELE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxLQUFLLENBQUM7UUFFNUIsdURBQXVEO1FBQ3ZELGdGQUFnRjtRQUNoRixJQUFJLG9DQUFjLENBQUMsSUFBSSxFQUFFLHlCQUF5QixFQUFFO1lBQ2xELFFBQVEsRUFBRTtnQkFDUixJQUFJLEVBQUUsd0JBQXdCO2dCQUM5QixTQUFTLEVBQUUsU0FBUztnQkFDcEIsTUFBTSxFQUFFO29CQUNOLHdCQUF3QixFQUFFLE1BQU07b0JBQ2hDLDZCQUE2QixFQUFFLGdCQUFnQjtvQkFDL0MsOEJBQThCLEVBQUUsT0FBTztvQkFDdkMsMkJBQTJCLEVBQUUsWUFBWTtpQkFDMUM7Z0JBQ0QsV0FBVyxFQUFFO29CQUNYLDhCQUE4QixFQUFFLEdBQUc7aUJBQ3BDO2FBQ0Y7WUFDRCxJQUFJLEVBQUU7Z0JBQ0osOERBQThEO2dCQUM5RCwyRUFBMkU7Z0JBQzNFLGVBQWUsRUFBRSxRQUFRO2dCQUV6QixnRkFBZ0Y7Z0JBQ2hGLGNBQWMsRUFBRTtvQkFDZCxJQUFJLEVBQUUsMEJBQTBCO29CQUNoQyxJQUFJLEVBQUUsMERBQW9DLENBQUMsb0JBQW9CO2lCQUNoRTtnQkFFRCx3REFBd0Q7Z0JBQ3hELE1BQU0sRUFBRTtvQkFDTixJQUFJLEVBQUUsSUFBSSxDQUFDLFVBQVU7b0JBQ3JCLGNBQWMsRUFBRSw0REFBc0MsQ0FBQyxLQUFLO2lCQUM3RDtnQkFFRCx3RUFBd0U7Z0JBQ3hFLFFBQVEsRUFBRTtvQkFDUjt3QkFDRSxPQUFPLEVBQUU7NEJBQ1AsR0FBRyxFQUFFLDJCQUEyQjt5QkFDakM7cUJBQ0Y7aUJBQ0Y7YUFDRjtTQUNGLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQXBERCxnRUFvREMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7XG4gIEV4dGVybmFsU2VjcmV0LFxuICBFeHRlcm5hbFNlY3JldFNwZWNUYXJnZXRDcmVhdGlvblBvbGljeSxcbiAgRXh0ZXJuYWxTZWNyZXRTcGVjU2VjcmV0U3RvcmVSZWZLaW5kLFxufSBmcm9tICcuLi9pbXBvcnRzL2V4dGVybmFsLXNlY3JldHMuaW8nO1xuaW1wb3J0IHsgTW9uaXRvcmluZ0NvbmZpZyB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGludGVyZmFjZSBMb2tpUzNDcmVkZW50aWFsc1Byb3BzIHtcbiAgbmFtZXNwYWNlOiBzdHJpbmc7XG4gIGNvbmZpZzogTW9uaXRvcmluZ0NvbmZpZztcbn1cblxuLyoqXG4gKiBDcmVhdGVzIEV4dGVybmFsU2VjcmV0IGZvciBMb2tpIFMzIGNyZWRlbnRpYWxzLlxuICpcbiAqIFRoaXMgY29uc3RydWN0IHJlcGxpY2F0ZXMgSGV0em5lciBTMyBjcmVkZW50aWFscyBmcm9tIGNyb3NzcGxhbmUtc3lzdGVtXG4gKiBuYW1lc3BhY2UgdG8gbW9uaXRvcmluZyBuYW1lc3BhY2UgZm9yIExva2kncyBvYmplY3Qgc3RvcmFnZS5cbiAqXG4gKiBQcmVyZXF1aXNpdGVzOlxuICogLSBFeHRlcm5hbCBTZWNyZXRzIE9wZXJhdG9yIGluc3RhbGxlZFxuICogLSBDbHVzdGVyU2VjcmV0U3RvcmUgJ2hldHpuZXItczMtY2x1c3Rlci1zdG9yZScgZXhpc3RzIChwb2ludHMgdG8gY3Jvc3NwbGFuZS1zeXN0ZW0pXG4gKiAtIFNlY3JldCAnaGV0em5lci1zMy1jcmVkcy1zdGFuZGFyZCcgZXhpc3RzIGluIGNyb3NzcGxhbmUtc3lzdGVtIG5hbWVzcGFjZVxuICpcbiAqIEdlbmVyYXRlZCBTZWNyZXQ6XG4gKiAtIE5hbWU6IGxva2ktczMtY3JlZGVudGlhbHNcbiAqIC0gS2V5czogQVdTX0FDQ0VTU19LRVlfSUQsIEFXU19TRUNSRVRfQUNDRVNTX0tFWVxuICpcbiAqIFN5bmMgV2F2ZTogMSAoZXh0ZXJuYWwgZGVwZW5kZW5jaWVzIC0gbXVzdCBleGlzdCBiZWZvcmUgTG9raSBzdGFydHMpXG4gKi9cbmV4cG9ydCBjbGFzcyBMb2tpUzNDcmVkZW50aWFsc0NvbnN0cnVjdCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIHB1YmxpYyByZWFkb25seSBzZWNyZXROYW1lID0gJ2xva2ktczMtY3JlZGVudGlhbHMnO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBMb2tpUzNDcmVkZW50aWFsc1Byb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGNvbnN0IHsgbmFtZXNwYWNlIH0gPSBwcm9wcztcblxuICAgIC8vIENyZWF0ZSBFeHRlcm5hbFNlY3JldCB0aGF0IHJlcGxpY2F0ZXMgUzMgY3JlZGVudGlhbHNcbiAgICAvLyBXYXZlIDE6IEV4dGVybmFsIERlcGVuZGVuY2llcyAtIGNyZWRlbnRpYWxzIG11c3QgZXhpc3QgYmVmb3JlIExva2kgY29tcG9uZW50c1xuICAgIG5ldyBFeHRlcm5hbFNlY3JldCh0aGlzLCAnbG9raS1zMy1leHRlcm5hbC1zZWNyZXQnLCB7XG4gICAgICBtZXRhZGF0YToge1xuICAgICAgICBuYW1lOiAnbG9raS1zMy1jcmVkZW50aWFscy1lcycsXG4gICAgICAgIG5hbWVzcGFjZTogbmFtZXNwYWNlLFxuICAgICAgICBsYWJlbHM6IHtcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vbmFtZSc6ICdsb2tpJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50JzogJ3MzLWNyZWRlbnRpYWxzJyxcbiAgICAgICAgICAnYXBwLmt1YmVybmV0ZXMuaW8vbWFuYWdlZC1ieSc6ICdjZGs4cycsXG4gICAgICAgICAgJ2FwcC5rdWJlcm5ldGVzLmlvL3BhcnQtb2YnOiAnbW9uaXRvcmluZycsXG4gICAgICAgIH0sXG4gICAgICAgIGFubm90YXRpb25zOiB7XG4gICAgICAgICAgJ2FyZ29jZC5hcmdvcHJvai5pby9zeW5jLXdhdmUnOiAnMScsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgc3BlYzoge1xuICAgICAgICAvLyBSZWZyZXNoIGNyZWRlbnRpYWxzIGV2ZXJ5IGhvdXIgKGF1dG9tYXRpYyByb3RhdGlvbiBzdXBwb3J0KVxuICAgICAgICAvLyBVc2UgZnVsbCBmb3JtYXQgdG8gbWF0Y2ggS3ViZXJuZXRlcyBub3JtYWxpemF0aW9uIGFuZCBhdm9pZCBBcmdvQ0QgZHJpZnRcbiAgICAgICAgcmVmcmVzaEludGVydmFsOiAnMWgwbTBzJyxcblxuICAgICAgICAvLyBVc2UgZXhpc3RpbmcgQ2x1c3RlclNlY3JldFN0b3JlIGZvciBIZXR6bmVyIFMzIChpbmZyYXN0cnVjdHVyZS1sZXZlbCBzZWNyZXRzKVxuICAgICAgICBzZWNyZXRTdG9yZVJlZjoge1xuICAgICAgICAgIG5hbWU6ICdoZXR6bmVyLXMzLWNsdXN0ZXItc3RvcmUnLFxuICAgICAgICAgIGtpbmQ6IEV4dGVybmFsU2VjcmV0U3BlY1NlY3JldFN0b3JlUmVmS2luZC5DTFVTVEVSX1NFQ1JFVF9TVE9SRSxcbiAgICAgICAgfSxcblxuICAgICAgICAvLyBUYXJnZXQgc2VjcmV0IHRoYXQgTG9raSB3aWxsIGNvbnN1bWUgdmlhIGV4dHJhRW52RnJvbVxuICAgICAgICB0YXJnZXQ6IHtcbiAgICAgICAgICBuYW1lOiB0aGlzLnNlY3JldE5hbWUsXG4gICAgICAgICAgY3JlYXRpb25Qb2xpY3k6IEV4dGVybmFsU2VjcmV0U3BlY1RhcmdldENyZWF0aW9uUG9saWN5Lk9XTkVSLFxuICAgICAgICB9LFxuXG4gICAgICAgIC8vIEZldGNoIFMzIGNyZWRlbnRpYWxzIGZyb20gY3Jvc3NwbGFuZS1zeXN0ZW0vaGV0em5lci1zMy1jcmVkcy1zdGFuZGFyZFxuICAgICAgICBkYXRhRnJvbTogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGV4dHJhY3Q6IHtcbiAgICAgICAgICAgICAga2V5OiAnaGV0em5lci1zMy1jcmVkcy1zdGFuZGFyZCcsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgIH0pO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import { MonitoringConfig } from '../types';
|
|
3
|
+
export interface LokiProps {
|
|
4
|
+
namespace: string;
|
|
5
|
+
config: MonitoringConfig;
|
|
6
|
+
s3CredentialsSecretName: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Creates Loki HelmChart for log aggregation.
|
|
10
|
+
*
|
|
11
|
+
* This construct deploys Loki in SimpleScalable mode with:
|
|
12
|
+
* - Backend (2 replicas) - Index and compaction
|
|
13
|
+
* - Read (2 replicas) - Query processing
|
|
14
|
+
* - Write (2 replicas) - Log ingestion
|
|
15
|
+
* - Gateway (1 replica) - HTTP API endpoint
|
|
16
|
+
* - S3 storage backend (Hetzner Object Storage)
|
|
17
|
+
*
|
|
18
|
+
* Prerequisites:
|
|
19
|
+
* - Namespace exists
|
|
20
|
+
* - PriorityClass 'high-priority' exists
|
|
21
|
+
* - Longhorn storage class available
|
|
22
|
+
* - S3 bucket exists (via Crossplane)
|
|
23
|
+
* - S3 credentials secret exists (via LokiS3CredentialsConstruct)
|
|
24
|
+
*
|
|
25
|
+
* Sync Wave: 2 (core services - after S3 credentials secret)
|
|
26
|
+
*/
|
|
27
|
+
export declare class LokiConstruct extends Construct {
|
|
28
|
+
constructor(scope: Construct, id: string, props: LokiProps);
|
|
29
|
+
private generateHelmValues;
|
|
30
|
+
}
|