From 92cb0341557cd1d0e57d940d5cbb23ec5f52134e Mon Sep 17 00:00:00 2001 From: = Date: Wed, 21 May 2025 20:00:38 +0530 Subject: [PATCH 1/6] feat: added sentinel sink --- sink/redis-sentinel/README.md | 20 +++ .../config/sentinel/sentinel.conf | 18 ++ .../docker-compose.sentinel.yml | 166 ++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 sink/redis-sentinel/README.md create mode 100644 sink/redis-sentinel/config/sentinel/sentinel.conf create mode 100644 sink/redis-sentinel/docker-compose.sentinel.yml diff --git a/sink/redis-sentinel/README.md b/sink/redis-sentinel/README.md new file mode 100644 index 000000000..91d5949c6 --- /dev/null +++ b/sink/redis-sentinel/README.md @@ -0,0 +1,20 @@ +## Sink for Redis Sentinel + +1. Create a `.env` from `.env.example` +2. The HOST_IP value must be your host ip, so that redis inside the containers can connect to it and switch over as needed. + +To test Sentinel is working correctly + +1. Run + +``` +docker exec -it sentinel-2 redis-cli -p 26379 sentinel get-master-addr-by-name mymaster +``` + +2. Run + +``` +docker-compose -f docker-compose.sentinel.yml stop redis-master +``` + +3. Again running step 1 should show the other replica port. diff --git a/sink/redis-sentinel/config/sentinel/sentinel.conf b/sink/redis-sentinel/config/sentinel/sentinel.conf new file mode 100644 index 000000000..d84cf9af7 --- /dev/null +++ b/sink/redis-sentinel/config/sentinel/sentinel.conf @@ -0,0 +1,18 @@ +port 26379 +sentinel resolve-hostnames yes +sentinel monitor mymaster 172.30.0.2 6379 2 +sentinel down-after-milliseconds mymaster 5000 +sentinel failover-timeout mymaster 60000 + +# Generated by CONFIG REWRITE +latency-tracking-info-percentiles 50 99 99.9 +dir "/data" +user default on nopass sanitize-payload ~* &* +@all +sentinel myid 19849dc6cc6e756dfb0db909c44f0a2f8f5bcbe3 +sentinel config-epoch mymaster 0 +sentinel leader-epoch mymaster 0 +sentinel current-epoch 0 + +sentinel known-replica mymaster 172.30.0.3 6379 + +sentinel known-replica mymaster 172.30.0.4 6379 diff --git a/sink/redis-sentinel/docker-compose.sentinel.yml b/sink/redis-sentinel/docker-compose.sentinel.yml new file mode 100644 index 000000000..df30c152b --- /dev/null +++ b/sink/redis-sentinel/docker-compose.sentinel.yml @@ -0,0 +1,166 @@ +version: "3.8" + +services: + redis-master: + image: redis:latest + container_name: redis-master + hostname: redis-master + ports: + - "6380:6379" + volumes: + - ./data/master:/data + command: + [ + "redis-server", + "--appendonly", + "yes", + "--repl-diskless-load", + "on-empty-db", + "--replica-announce-ip", + "${HOST_IP}", + "--replica-announce-port", + "6380", + "--protected-mode", + "no", + ] + networks: + redis-net: + ipv4_address: 172.21.0.3 + + redis-slave-1: + image: redis:latest + container_name: redis-slave-1 + hostname: redis-slave-1 + depends_on: + - redis-master + ports: + - "6381:6379" + volumes: + - ./data/slave1:/data + command: + [ + "redis-server", + "--appendonly", + "yes", + "--replicaof", + "redis-master", + "6379", + "--repl-diskless-load", + "on-empty-db", + "--replica-announce-ip", + "${HOST_IP}", + "--replica-announce-port", + "6381", + "--protected-mode", + "no", + ] + networks: + redis-net: + ipv4_address: 172.21.0.4 + + redis-slave-2: + image: redis:latest + container_name: redis-slave-2 + hostname: redis-slave-2 + depends_on: + - redis-master + ports: + - "6382:6379" + volumes: + - ./data/slave2:/data + command: + [ + "redis-server", + "--appendonly", + "yes", + "--replicaof", + "redis-master", + "6379", + "--repl-diskless-load", + "on-empty-db", + "--replica-announce-ip", + "${HOST_IP}", + "--replica-announce-port", + "6382", + "--protected-mode", + "no", + ] + networks: + redis-net: + ipv4_address: 172.21.0.5 + + sentinel-1: + image: redis:latest + container_name: sentinel-1 + hostname: sentinel-1 + depends_on: + - redis-master + ports: + - "26379:26379" + command: > + sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf && + echo "sentinel monitor mymaster ${HOST_IP} 6380 2" >> /etc/sentinel.conf && + echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf && + echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf && + echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf && + echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf && + redis-sentinel /etc/sentinel.conf' + networks: + redis-net: + ipv4_address: 172.21.0.6 + + sentinel-2: + image: redis:latest + container_name: sentinel-2 + hostname: sentinel-2 + depends_on: + - redis-master + ports: + - "26380:26379" + command: > + sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf && + echo "sentinel monitor mymaster ${HOST_IP} 6380 2" >> /etc/sentinel.conf && + echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf && + echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf && + echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf && + echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf && + redis-sentinel /etc/sentinel.conf' + networks: + redis-net: + ipv4_address: 172.21.0.7 + + sentinel-3: + image: redis:latest + container_name: sentinel-3 + hostname: sentinel-3 + depends_on: + - redis-master + ports: + - "26381:26379" + command: > + sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf && + echo "sentinel monitor mymaster ${HOST_IP} 6380 2" >> /etc/sentinel.conf && + echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf && + echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf && + echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf && + echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf && + redis-sentinel /etc/sentinel.conf' + networks: + redis-net: + ipv4_address: 172.21.0.8 + + redisinsight: + image: redis/redisinsight:latest + container_name: redisinsight + ports: + - "5540:5540" + networks: + redis-net: + ipv4_address: 172.21.0.9 + +networks: + redis-net: + driver: bridge + ipam: + config: + - subnet: 172.21.0.0/16 From 3ac3710273479e2c70da723d71dd44100be98826 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 21 May 2025 20:01:04 +0530 Subject: [PATCH 2/6] feat: added sentinel suppor for backend --- backend/e2e-test/vitest-environment-knex.ts | 4 +-- backend/src/keystore/keystore.ts | 7 ++--- backend/src/lib/config/env.ts | 28 +++++++++++++++---- backend/src/lib/config/redis.ts | 24 ++++++++++++++++ backend/src/main.ts | 8 +++--- backend/src/queue/queue-service.ts | 6 ++-- backend/src/server/boot-strap-check.ts | 7 +++-- backend/src/server/config/rateLimiter.ts | 6 ++-- .../certificate/certificate-service.ts | 2 +- 9 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 backend/src/lib/config/redis.ts diff --git a/backend/e2e-test/vitest-environment-knex.ts b/backend/e2e-test/vitest-environment-knex.ts index 46b322349..d3e6bb2e1 100644 --- a/backend/e2e-test/vitest-environment-knex.ts +++ b/backend/e2e-test/vitest-environment-knex.ts @@ -55,8 +55,8 @@ export default { }); const smtp = mockSmtpServer(); - const queue = queueServiceFactory(envConfig.REDIS_URL, { dbConnectionUrl: envConfig.DB_CONNECTION_URI }); - const keyStore = keyStoreFactory(envConfig.REDIS_URL); + const queue = queueServiceFactory(envConfig, { dbConnectionUrl: envConfig.DB_CONNECTION_URI }); + const keyStore = keyStoreFactory(envConfig); const hsmModule = initializeHsmModule(envConfig); hsmModule.initialize(); diff --git a/backend/src/keystore/keystore.ts b/backend/src/keystore/keystore.ts index 6da6c4fa4..b253a4c6c 100644 --- a/backend/src/keystore/keystore.ts +++ b/backend/src/keystore/keystore.ts @@ -1,5 +1,4 @@ -import { Redis } from "ioredis"; - +import { buildRedisFromConfig, TRedisConfigKeys } from "@app/lib/config/redis"; import { pgAdvisoryLockHashText } from "@app/lib/crypto/hashtext"; import { applyJitter } from "@app/lib/dates"; import { delay as delayMs } from "@app/lib/delay"; @@ -66,8 +65,8 @@ type TWaitTillReady = { jitter?: number; }; -export const keyStoreFactory = (redisUrl: string) => { - const redis = new Redis(redisUrl); +export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys) => { + const redis = buildRedisFromConfig(redisConfigKeys); const redisLock = new Redlock([redis], { retryCount: 2, retryDelay: 200 }); const setItem = async (key: string, value: string | number | Buffer, prefix?: string) => diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index e38dbcfb5..263b65ce8 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -30,7 +30,19 @@ const envSchema = z .enum(["true", "false"]) .default("false") .transform((el) => el === "true"), - REDIS_URL: zpStr(z.string()), + REDIS_URL: zpStr(z.string().optional()), + REDIS_SENTINEL_HOSTS: zpStr( + z + .string() + .optional() + .describe("Comma-separated list of Sentinel host:port pairs. Eg: 192.168.65.254:26379,192.168.65.254:26380") + ), + REDIS_SENTINEL_MASTER_NAME: zpStr( + z.string().optional().default("mymaster").describe("The name of the Redis master set monitored by Sentinel") + ), + REDIS_SENTINEL_ENABLE_TLS: zodStrBool.optional().describe(" Whether to use TLS/SSL for Redis Sentinel connection"), + REDIS_SENTINEL_USERNAME: zpStr(z.string().optional().describe("Authentication username for Redis Sentinel")), + REDIS_SENTINEL_PASSWORD: zpStr(z.string().optional().describe("Authentication password for Redis Sentinel")), HOST: zpStr(z.string().default("localhost")), DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database connection string")).default( `postgresql://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}` @@ -256,26 +268,32 @@ const envSchema = z (data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY), "Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined." ) + .refine( + (data) => Boolean(data.REDIS_URL) || Boolean(data.REDIS_SENTINEL_HOSTS), + "Either REDIS_URL or REDIS_SENTINEL_HOSTS must be defined." + ) .transform((data) => ({ ...data, - DB_READ_REPLICAS: data.DB_READ_REPLICAS ? databaseReadReplicaSchema.parse(JSON.parse(data.DB_READ_REPLICAS)) : undefined, isCloud: Boolean(data.LICENSE_SERVER_KEY), isSmtpConfigured: Boolean(data.SMTP_HOST), - isRedisConfigured: Boolean(data.REDIS_URL), + isRedisConfigured: Boolean(data.REDIS_URL || data.REDIS_SENTINEL_HOSTS), isDevelopmentMode: data.NODE_ENV === "development", isRotationDevelopmentMode: data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE, isProductionMode: data.NODE_ENV === "production" || IS_PACKAGED, - + isRedisSentinelMode: Boolean(data.REDIS_SENTINEL_HOSTS), + REDIS_SENTINEL_HOSTS: data.REDIS_SENTINEL_HOSTS?.split(",").map((el) => { + const [host, port] = el.split(":"); + return { host: host.trim(), port: Number(port.trim()) }; + }), isSecretScanningConfigured: Boolean(data.SECRET_SCANNING_GIT_APP_ID) && Boolean(data.SECRET_SCANNING_PRIVATE_KEY) && Boolean(data.SECRET_SCANNING_WEBHOOK_SECRET), isHsmConfigured: Boolean(data.HSM_LIB_PATH) && Boolean(data.HSM_PIN) && Boolean(data.HSM_KEY_LABEL) && data.HSM_SLOT !== undefined, - samlDefaultOrgSlug: data.DEFAULT_SAML_ORG_SLUG, SECRET_SCANNING_ORG_WHITELIST: data.SECRET_SCANNING_ORG_WHITELIST?.split(",") })); diff --git a/backend/src/lib/config/redis.ts b/backend/src/lib/config/redis.ts new file mode 100644 index 000000000..987518dd5 --- /dev/null +++ b/backend/src/lib/config/redis.ts @@ -0,0 +1,24 @@ +import { Redis } from "ioredis"; + +export type TRedisConfigKeys = Partial<{ + REDIS_URL: string; + REDIS_SENTINEL_HOSTS: { host: string; port: number }[]; + REDIS_SENTINEL_MASTER_NAME: string; + REDIS_SENTINEL_ENABLE_TLS: boolean; + REDIS_SENTINEL_USERNAME: string; + REDIS_SENTINEL_PASSWORD: string; +}>; + +export const buildRedisFromConfig = (cfg: TRedisConfigKeys) => { + if (cfg.REDIS_URL) return new Redis(cfg.REDIS_URL, { maxRetriesPerRequest: null }); + + return new Redis({ + // refine at tope will catch this case + sentinels: cfg.REDIS_SENTINEL_HOSTS!, + name: cfg.REDIS_SENTINEL_MASTER_NAME!, + maxRetriesPerRequest: null, + sentinelUsername: cfg.REDIS_SENTINEL_USERNAME, + sentinelPassword: cfg.REDIS_SENTINEL_PASSWORD, + enableTLSForSentinelMode: cfg.REDIS_SENTINEL_ENABLE_TLS + }); +}; diff --git a/backend/src/main.ts b/backend/src/main.ts index c3b5a0900..d141b62d5 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -1,7 +1,6 @@ import "./lib/telemetry/instrumentation"; import dotenv from "dotenv"; -import { Redis } from "ioredis"; import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns"; @@ -9,6 +8,7 @@ import { runMigrations } from "./auto-start-migrations"; import { initAuditLogDbConnection, initDbConnection } from "./db"; import { keyStoreFactory } from "./keystore/keystore"; import { formatSmtpConfig, initEnvConfig } from "./lib/config/env"; +import { buildRedisFromConfig } from "./lib/config/redis"; import { removeTemporaryBaseDirectory } from "./lib/files"; import { initLogger } from "./lib/logger"; import { queueServiceFactory } from "./queue"; @@ -44,15 +44,15 @@ const run = async () => { const smtp = smtpServiceFactory(formatSmtpConfig()); - const queue = queueServiceFactory(envConfig.REDIS_URL, { + const queue = queueServiceFactory(envConfig, { dbConnectionUrl: envConfig.DB_CONNECTION_URI, dbRootCert: envConfig.DB_ROOT_CERT }); await queue.initialize(); - const keyStore = keyStoreFactory(envConfig.REDIS_URL); - const redis = new Redis(envConfig.REDIS_URL); + const keyStore = keyStoreFactory(envConfig); + const redis = buildRedisFromConfig(envConfig); const hsmModule = initializeHsmModule(envConfig); hsmModule.initialize(); diff --git a/backend/src/queue/queue-service.ts b/backend/src/queue/queue-service.ts index 807d6c286..e55b1f38e 100644 --- a/backend/src/queue/queue-service.ts +++ b/backend/src/queue/queue-service.ts @@ -1,5 +1,4 @@ import { Job, JobsOptions, Queue, QueueOptions, RepeatOptions, Worker, WorkerListener } from "bullmq"; -import Redis from "ioredis"; import PgBoss, { WorkOptions } from "pg-boss"; import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas"; @@ -13,6 +12,7 @@ import { TScanPushEventPayload } from "@app/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-queue-types"; import { getConfig } from "@app/lib/config/env"; +import { buildRedisFromConfig, TRedisConfigKeys } from "@app/lib/config/redis"; import { logger } from "@app/lib/logger"; import { TFailedIntegrationSyncEmailsPayload, @@ -249,10 +249,10 @@ export type TQueueJobTypes = { export type TQueueServiceFactory = ReturnType; export const queueServiceFactory = ( - redisUrl: string, + redisCfg: TRedisConfigKeys, { dbConnectionUrl, dbRootCert }: { dbConnectionUrl: string; dbRootCert?: string } ) => { - const connection = new Redis(redisUrl, { maxRetriesPerRequest: null }); + const connection = buildRedisFromConfig(redisCfg); const queueContainer = {} as Record< QueueName, Queue diff --git a/backend/src/server/boot-strap-check.ts b/backend/src/server/boot-strap-check.ts index 7db2a71e8..989a84222 100644 --- a/backend/src/server/boot-strap-check.ts +++ b/backend/src/server/boot-strap-check.ts @@ -1,9 +1,9 @@ /* eslint-disable no-console */ -import { Redis } from "ioredis"; import { Knex } from "knex"; import { createTransport } from "nodemailer"; import { formatSmtpConfig, getConfig } from "@app/lib/config/env"; +import { buildRedisFromConfig } from "@app/lib/config/redis"; import { logger } from "@app/lib/logger"; import { getServerCfg } from "@app/services/super-admin/super-admin-service"; @@ -65,12 +65,15 @@ export const bootstrapCheck = async ({ db }: BootstrapOpt) => { }); console.log("Testing redis connection"); - const redis = new Redis(appCfg.REDIS_URL); + const redis = buildRedisFromConfig(appCfg); const redisPing = await redis?.ping(); if (!redisPing) { console.error("Redis - Failed to connect"); } else { console.error("Redis successfully connected"); + if (appCfg.isRedisSentinelMode) { + console.log("Redis Sentinel Mode"); + } redis.disconnect(); } diff --git a/backend/src/server/config/rateLimiter.ts b/backend/src/server/config/rateLimiter.ts index b12c9b0d3..7b4b9a99b 100644 --- a/backend/src/server/config/rateLimiter.ts +++ b/backend/src/server/config/rateLimiter.ts @@ -1,14 +1,12 @@ import type { RateLimitOptions, RateLimitPluginOptions } from "@fastify/rate-limit"; -import { Redis } from "ioredis"; import { getConfig } from "@app/lib/config/env"; +import { buildRedisFromConfig } from "@app/lib/config/redis"; import { RateLimitError } from "@app/lib/errors"; export const globalRateLimiterCfg = (): RateLimitPluginOptions => { const appCfg = getConfig(); - const redis = appCfg.isRedisConfigured - ? new Redis(appCfg.REDIS_URL, { connectTimeout: 500, maxRetriesPerRequest: 1 }) - : null; + const redis = appCfg.isRedisConfigured ? buildRedisFromConfig(appCfg) : null; return { errorResponseBuilder: (_, context) => { diff --git a/backend/src/services/certificate/certificate-service.ts b/backend/src/services/certificate/certificate-service.ts index 292b5f109..be3f8677e 100644 --- a/backend/src/services/certificate/certificate-service.ts +++ b/backend/src/services/certificate/certificate-service.ts @@ -8,6 +8,7 @@ import { ProjectPermissionCertificateActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; +import { NotFoundError } from "@app/lib/errors"; import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal"; import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal"; import { TCertificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal"; @@ -29,7 +30,6 @@ import { TGetCertPrivateKeyDTO, TRevokeCertDTO } from "./certificate-types"; -import { NotFoundError } from "@app/lib/errors"; type TCertificateServiceFactoryDep = { certificateDAL: Pick; From bb2a70b986b817a041e36af5ee916b2e77ba8541 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 21 May 2025 20:01:13 +0530 Subject: [PATCH 3/6] feat: updated doc --- docs/self-hosting/configuration/envars.mdx | 97 ++++++++++++++++------ 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/docs/self-hosting/configuration/envars.mdx b/docs/self-hosting/configuration/envars.mdx index b63c58d3a..1c78a05ea 100644 --- a/docs/self-hosting/configuration/envars.mdx +++ b/docs/self-hosting/configuration/envars.mdx @@ -32,14 +32,16 @@ Used to configure platform-specific security and operational settings Specifies the network interface Infisical will bind to when accepting incoming connections. - By default, Infisical binds to `localhost`, which restricts access to connections from the same machine. +By default, Infisical binds to `localhost`, which restricts access to connections from the same machine. - To make the application accessible externally (e.g., for self-hosted deployments), set this to `0.0.0.0`, which tells the server to listen on all network interfaces. +To make the application accessible externally (e.g., for self-hosted deployments), set this to `0.0.0.0`, which tells the server to listen on all network interfaces. + +Example values: + +- `localhost` (default, same as `127.0.0.1`) +- `0.0.0.0` (all interfaces, accessible externally) +- `192.168.1.100` (specific interface IP) - Example values: - - `localhost` (default, same as `127.0.0.1`) - - `0.0.0.0` (all interfaces, accessible externally) - - `192.168.1.100` (specific interface IP) @@ -86,8 +88,9 @@ The platform utilizes Postgres to persist all of its data and Redis for caching ### PostgreSQL - Please note that the database user you create must be granted all privileges on the Infisical database. - This includes the ability to create new schemas, create, update, delete, modify tables and indexes, etc. + Please note that the database user you create must be granted all privileges + on the Infisical database. This includes the ability to create new schemas, + create, update, delete, modify tables and indexes, etc. @@ -95,9 +98,8 @@ The platform utilizes Postgres to persist all of its data and Redis for caching - Configure the SSL certificate for securing a Postgres connection by first encoding it in base64. - Use the command below to encode your certificate: - `echo "" | base64` + Configure the SSL certificate for securing a Postgres connection by first + encoding it in base64. Use the command below to encode your certificate: @@ -122,9 +124,42 @@ DB_READ_REPLICAS=[{"DB_CONNECTION_URI":""}] ### Redis - - Redis connection string. - +Redis is required for smooth operation of Infisical. + + + + + Redis connection string. + + + + + Comma-separated list of Sentinel host:port pairs. ``` + 192.168.65.254:26379,192.168.65.254:26380 ``` + + + The name of the Redis master set monitored by Sentinel + + + Whether to use TLS/SSL for Redis Sentinel connection + + + Authentication username for Redis Sentinel + + + Authentication password for Redis Sentinel + + + ## Email Service @@ -222,7 +257,7 @@ SMTP_FROM_NAME=Infisical This will be used to verify the email you are sending from. ![Create SES identity](../../images/self-hosting/configuration/email/ses-create-identity.png) - If you AWS SES is under sandbox mode, you will only be able to send emails to verified identies. + If you AWS SES is under sandbox mode, you will only be able to send emails to verified identies. @@ -388,9 +423,9 @@ SMTP_FROM_NAME=Infisical - + 1. Create an account and configure [SMTP2Go](https://www.smtp2go.com/) to send emails. -2. Turn on SMTP authentication +2. Turn on SMTP authentication ``` SMTP_HOST=mail.smtp2go.com SMTP_PORT=You can use one of the following ports: 2525, 80, 25, 8025, or 587 @@ -401,7 +436,7 @@ SMTP_FROM_NAME=Infisical ``` {" "} - + Optional (for TLS/SSL): TLS: Available on the same ports (2525, 80, 25, 8025, or 587) @@ -632,13 +667,27 @@ To help you sync secrets from Infisical to services such as Github and Gitlab, I The App ID of your GitHub App. - - The slug of your GitHub App. - +{" "} - - A private key for your GitHub App. - + + The slug of your GitHub App. + + +{" "} + + + A private key for your GitHub App. + The webhook secret of your GitHub App. From c985690e9a6865ad7810bc8e20953f8398c24c5a Mon Sep 17 00:00:00 2001 From: = Date: Wed, 21 May 2025 20:11:59 +0530 Subject: [PATCH 4/6] feat: reptile review changes --- backend/src/lib/config/env.ts | 12 +++++++----- backend/src/server/boot-strap-check.ts | 2 +- sink/redis-sentinel/.env.example | 1 + .../config/sentinel/sentinel.conf | 18 ------------------ 4 files changed, 9 insertions(+), 24 deletions(-) create mode 100644 sink/redis-sentinel/.env.example delete mode 100644 sink/redis-sentinel/config/sentinel/sentinel.conf diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 263b65ce8..c9e01cef5 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -40,7 +40,7 @@ const envSchema = z REDIS_SENTINEL_MASTER_NAME: zpStr( z.string().optional().default("mymaster").describe("The name of the Redis master set monitored by Sentinel") ), - REDIS_SENTINEL_ENABLE_TLS: zodStrBool.optional().describe(" Whether to use TLS/SSL for Redis Sentinel connection"), + REDIS_SENTINEL_ENABLE_TLS: zodStrBool.optional().describe("Whether to use TLS/SSL for Redis Sentinel connection"), REDIS_SENTINEL_USERNAME: zpStr(z.string().optional().describe("Authentication username for Redis Sentinel")), REDIS_SENTINEL_PASSWORD: zpStr(z.string().optional().describe("Authentication password for Redis Sentinel")), HOST: zpStr(z.string().default("localhost")), @@ -284,10 +284,12 @@ const envSchema = z isRotationDevelopmentMode: data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE, isProductionMode: data.NODE_ENV === "production" || IS_PACKAGED, isRedisSentinelMode: Boolean(data.REDIS_SENTINEL_HOSTS), - REDIS_SENTINEL_HOSTS: data.REDIS_SENTINEL_HOSTS?.split(",").map((el) => { - const [host, port] = el.split(":"); - return { host: host.trim(), port: Number(port.trim()) }; - }), + REDIS_SENTINEL_HOSTS: data.REDIS_SENTINEL_HOSTS?.trim() + ?.split(",") + .map((el) => { + const [host, port] = el.trim().split(":"); + return { host: host.trim(), port: Number(port.trim()) }; + }), isSecretScanningConfigured: Boolean(data.SECRET_SCANNING_GIT_APP_ID) && Boolean(data.SECRET_SCANNING_PRIVATE_KEY) && diff --git a/backend/src/server/boot-strap-check.ts b/backend/src/server/boot-strap-check.ts index 989a84222..91c52d871 100644 --- a/backend/src/server/boot-strap-check.ts +++ b/backend/src/server/boot-strap-check.ts @@ -70,7 +70,7 @@ export const bootstrapCheck = async ({ db }: BootstrapOpt) => { if (!redisPing) { console.error("Redis - Failed to connect"); } else { - console.error("Redis successfully connected"); + console.log("Redis successfully connected"); if (appCfg.isRedisSentinelMode) { console.log("Redis Sentinel Mode"); } diff --git a/sink/redis-sentinel/.env.example b/sink/redis-sentinel/.env.example new file mode 100644 index 000000000..89dea292d --- /dev/null +++ b/sink/redis-sentinel/.env.example @@ -0,0 +1 @@ +HOST_IP= diff --git a/sink/redis-sentinel/config/sentinel/sentinel.conf b/sink/redis-sentinel/config/sentinel/sentinel.conf deleted file mode 100644 index d84cf9af7..000000000 --- a/sink/redis-sentinel/config/sentinel/sentinel.conf +++ /dev/null @@ -1,18 +0,0 @@ -port 26379 -sentinel resolve-hostnames yes -sentinel monitor mymaster 172.30.0.2 6379 2 -sentinel down-after-milliseconds mymaster 5000 -sentinel failover-timeout mymaster 60000 - -# Generated by CONFIG REWRITE -latency-tracking-info-percentiles 50 99 99.9 -dir "/data" -user default on nopass sanitize-payload ~* &* +@all -sentinel myid 19849dc6cc6e756dfb0db909c44f0a2f8f5bcbe3 -sentinel config-epoch mymaster 0 -sentinel leader-epoch mymaster 0 -sentinel current-epoch 0 - -sentinel known-replica mymaster 172.30.0.3 6379 - -sentinel known-replica mymaster 172.30.0.4 6379 From 04989372b13e60414ffadd6100664e1b43824ecb Mon Sep 17 00:00:00 2001 From: = Date: Wed, 21 May 2025 22:55:15 +0530 Subject: [PATCH 5/6] feat: resolved ts issue --- backend/e2e-test/vitest-environment-knex.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/e2e-test/vitest-environment-knex.ts b/backend/e2e-test/vitest-environment-knex.ts index d3e6bb2e1..92cf86e66 100644 --- a/backend/e2e-test/vitest-environment-knex.ts +++ b/backend/e2e-test/vitest-environment-knex.ts @@ -15,8 +15,8 @@ import { mockSmtpServer } from "./mocks/smtp"; import { initDbConnection } from "@app/db"; import { queueServiceFactory } from "@app/queue"; import { keyStoreFactory } from "@app/keystore/keystore"; -import { Redis } from "ioredis"; import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns"; +import { buildRedisFromConfig } from "@app/lib/config/redis"; dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true }); export default { @@ -30,7 +30,7 @@ export default { dbRootCert: envConfig.DB_ROOT_CERT }); - const redis = new Redis(envConfig.REDIS_URL); + const redis = buildRedisFromConfig(envConfig); await redis.flushdb("SYNC"); try { From 72088634d883308c8a9c73df5bc84c650b38044c Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Mon, 26 May 2025 18:40:31 -0400 Subject: [PATCH 6/6] update config file --- docs/self-hosting/configuration/envars.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/self-hosting/configuration/envars.mdx b/docs/self-hosting/configuration/envars.mdx index 1c78a05ea..bcdd28a1d 100644 --- a/docs/self-hosting/configuration/envars.mdx +++ b/docs/self-hosting/configuration/envars.mdx @@ -1,5 +1,5 @@ --- -title: "Configurations" +title: "Environment Variables" description: "Read how to configure environment variables for self-hosted Infisical." --- @@ -123,11 +123,10 @@ DB_READ_REPLICAS=[{"DB_CONNECTION_URI":""}] ### Redis - -Redis is required for smooth operation of Infisical. +Redis is used for caching and background tasks. You can use either a standalone Redis instance or a Redis Sentinel setup. - + Redis connection string.