Compare commits
125 Commits
test-db-re
...
infisical/
Author | SHA1 | Date | |
---|---|---|---|
|
87b571d6ff | ||
|
1e6af8ad8f | ||
|
a771ddf859 | ||
|
c4cd6909bb | ||
|
49642480d3 | ||
|
b667dccc0d | ||
|
fdda247120 | ||
|
ee8a88d062 | ||
|
33349839cd | ||
|
8f3883c7d4 | ||
|
38cfb7fd41 | ||
|
a331eb8dc4 | ||
|
2dcb409d3b | ||
|
39bcb73f3d | ||
|
52189111d7 | ||
|
f369761920 | ||
|
8eb22630b6 | ||
|
d650fd68c0 | ||
|
387c899193 | ||
|
37882e6344 | ||
|
68a1aa6f46 | ||
|
fa18ca41ac | ||
|
8485fdc1cd | ||
|
49ae2386c0 | ||
|
f2b1f3f0e7 | ||
|
69aa20e35c | ||
|
524c7ae78f | ||
|
e13f7a7486 | ||
|
1867fb2fc4 | ||
|
5dd144b97b | ||
|
b1b430e003 | ||
|
fb09980413 | ||
|
3b36cb8b3d | ||
|
be6a98d0bb | ||
|
f8e1ed09d2 | ||
|
5c71116be6 | ||
|
07cc4fd1ab | ||
|
74bdbc0724 | ||
|
a0d5c67456 | ||
|
db4f4d8f28 | ||
|
d6f6f51d16 | ||
|
79a0f3d701 | ||
|
46912c4c3c | ||
|
6636377cb5 | ||
|
26320ddce4 | ||
|
f5964040d7 | ||
|
dcaa7f1fce | ||
|
a4119ee1bb | ||
|
74f866715f | ||
|
667f696d26 | ||
|
5f3938c33d | ||
|
07845ad6af | ||
|
17fa72be13 | ||
|
bf3e93460a | ||
|
306709cde6 | ||
|
c41518c822 | ||
|
f0f2905789 | ||
|
212a7b49f0 | ||
|
22e3fcb43c | ||
|
93b65a1534 | ||
|
039882e78b | ||
|
f0f51089fe | ||
|
447141ab1f | ||
|
d2ba436338 | ||
|
ad0d281629 | ||
|
c8638479a8 | ||
|
8aa75484f3 | ||
|
66d70f5a25 | ||
|
8e7cf5f9ac | ||
|
f9f79cb69e | ||
|
4235be4be9 | ||
|
5c3f2e66fd | ||
|
a37b3ccede | ||
|
d64eb4b901 | ||
|
6e882aa46e | ||
|
bf4db0a9ff | ||
|
3a3e3a7afc | ||
|
cdba78b51d | ||
|
0c324e804c | ||
|
47aca3f3e2 | ||
|
31ef1a2183 | ||
|
66a6f9de71 | ||
|
6333eccc4a | ||
|
0af2b113df | ||
|
63a7941047 | ||
|
edeac08cb5 | ||
|
019b0ae09a | ||
|
1d00bb0a64 | ||
|
d96f1320ed | ||
|
50dbefeb48 | ||
|
56ac2c6780 | ||
|
c2f16da411 | ||
|
8223aee2ef | ||
|
5bd2af9621 | ||
|
b3df6ce6b5 | ||
|
e12eb5347d | ||
|
83a4426d31 | ||
|
3fd1fbc355 | ||
|
306d2b4bd9 | ||
|
c2c66af1f9 | ||
|
7ae65478aa | ||
|
b1594e65c6 | ||
|
0bce5b1daa | ||
|
207db93483 | ||
|
972f6a4887 | ||
|
6e1bece9d9 | ||
|
63e8bc1845 | ||
|
4f92663b66 | ||
|
a66a6790c0 | ||
|
bde853d280 | ||
|
acda627236 | ||
|
875afbb4d6 | ||
|
56f50a18dc | ||
|
801c438d05 | ||
|
baba411502 | ||
|
4c20ac6564 | ||
|
4e8556dec2 | ||
|
2d7b9ec1e4 | ||
|
8bb9ed4394 | ||
|
e4246ae85f | ||
|
5c0e5a8ae0 | ||
|
5e0d64525f | ||
|
8bcf936b91 | ||
|
1a2508d91a | ||
|
e81a77652f |
@@ -2,8 +2,7 @@ name: Rename Migrations
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
types: [closed]
|
||||
paths:
|
||||
- 'backend/src/db/migrations/**'
|
||||
|
||||
@@ -11,26 +10,39 @@ jobs:
|
||||
rename:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.merged == true
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get list of newly added files in migration folder
|
||||
run: git diff --name-status HEAD^ HEAD backend/src/db/migrations | grep '^A' | cut -f2 | xargs -n1 basename > added_files.txt
|
||||
run: |
|
||||
git diff --name-status HEAD^ HEAD backend/src/db/migrations | grep '^A' | cut -f2 | xargs -n1 basename > added_files.txt
|
||||
if [ ! -s added_files.txt ]; then
|
||||
echo "No new files added. Skipping"
|
||||
echo "SKIP_RENAME=true" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Script to rename migrations
|
||||
if: env.SKIP_RENAME != 'true'
|
||||
run: python .github/resources/rename_migration_files.py
|
||||
|
||||
- name: Commit and push changes
|
||||
if: env.SKIP_RENAME != 'true'
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
git add ./backend/src/db/migrations
|
||||
rm added_files.txt
|
||||
git commit -m "chore: renamed new migration files to latest timestamp (gh-action)"
|
||||
|
||||
- name: Push changes
|
||||
env:
|
||||
TOKEN: ${{ secrets.GH_PERSONAL_TOKEN }}
|
||||
run: |
|
||||
git push https://$GITHUB_ACTOR:$TOKEN@github.com/${{ github.repository }}.git HEAD:main
|
||||
|
||||
- name: Create Pull Request
|
||||
if: env.SKIP_RENAME != 'true'
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: 'chore: renamed new migration files to latest UTC (gh-action)'
|
||||
title: 'GH Action: rename new migration file timestamp'
|
||||
branch-suffix: timestamp
|
||||
|
2
backend/src/@types/fastify.d.ts
vendored
@@ -3,6 +3,7 @@ import "fastify";
|
||||
import { TUsers } from "@app/db/schemas";
|
||||
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
||||
import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
|
||||
import { TDynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
|
||||
import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
|
||||
import { TGroupServiceFactory } from "@app/ee/services/group/group-service";
|
||||
@@ -120,6 +121,7 @@ declare module "fastify" {
|
||||
scim: TScimServiceFactory;
|
||||
ldap: TLdapConfigServiceFactory;
|
||||
auditLog: TAuditLogServiceFactory;
|
||||
auditLogStream: TAuditLogStreamServiceFactory;
|
||||
secretScanning: TSecretScanningServiceFactory;
|
||||
license: TLicenseServiceFactory;
|
||||
trustedIp: TTrustedIpServiceFactory;
|
||||
|
8
backend/src/@types/knex.d.ts
vendored
@@ -7,6 +7,9 @@ import {
|
||||
TApiKeysUpdate,
|
||||
TAuditLogs,
|
||||
TAuditLogsInsert,
|
||||
TAuditLogStreams,
|
||||
TAuditLogStreamsInsert,
|
||||
TAuditLogStreamsUpdate,
|
||||
TAuditLogsUpdate,
|
||||
TAuthTokens,
|
||||
TAuthTokenSessions,
|
||||
@@ -404,6 +407,11 @@ declare module "knex/types/tables" {
|
||||
[TableName.LdapGroupMap]: Knex.CompositeTableType<TLdapGroupMaps, TLdapGroupMapsInsert, TLdapGroupMapsUpdate>;
|
||||
[TableName.OrgBot]: Knex.CompositeTableType<TOrgBots, TOrgBotsInsert, TOrgBotsUpdate>;
|
||||
[TableName.AuditLog]: Knex.CompositeTableType<TAuditLogs, TAuditLogsInsert, TAuditLogsUpdate>;
|
||||
[TableName.AuditLogStream]: Knex.CompositeTableType<
|
||||
TAuditLogStreams,
|
||||
TAuditLogStreamsInsert,
|
||||
TAuditLogStreamsUpdate
|
||||
>;
|
||||
[TableName.GitAppInstallSession]: Knex.CompositeTableType<
|
||||
TGitAppInstallSessions,
|
||||
TGitAppInstallSessionsInsert,
|
||||
|
@@ -1,10 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
}
|
||||
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
}
|
||||
|
28
backend/src/db/migrations/20240429154610_audit-log-index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const doesOrgIdExist = await knex.schema.hasColumn(TableName.AuditLog, "orgId");
|
||||
const doesProjectIdExist = await knex.schema.hasColumn(TableName.AuditLog, "projectId");
|
||||
const doesCreatedAtExist = await knex.schema.hasColumn(TableName.AuditLog, "createdAt");
|
||||
if (await knex.schema.hasTable(TableName.AuditLog)) {
|
||||
await knex.schema.alterTable(TableName.AuditLog, (t) => {
|
||||
if (doesProjectIdExist && doesCreatedAtExist) t.index(["projectId", "createdAt"]);
|
||||
if (doesOrgIdExist && doesCreatedAtExist) t.index(["orgId", "createdAt"]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
const doesOrgIdExist = await knex.schema.hasColumn(TableName.AuditLog, "orgId");
|
||||
const doesProjectIdExist = await knex.schema.hasColumn(TableName.AuditLog, "projectId");
|
||||
const doesCreatedAtExist = await knex.schema.hasColumn(TableName.AuditLog, "createdAt");
|
||||
|
||||
if (await knex.schema.hasTable(TableName.AuditLog)) {
|
||||
await knex.schema.alterTable(TableName.AuditLog, (t) => {
|
||||
if (doesProjectIdExist && doesCreatedAtExist) t.dropIndex(["projectId", "createdAt"]);
|
||||
if (doesOrgIdExist && doesCreatedAtExist) t.dropIndex(["orgId", "createdAt"]);
|
||||
});
|
||||
}
|
||||
}
|
28
backend/src/db/migrations/20240503101144_audit-log-stream.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.AuditLogStream))) {
|
||||
await knex.schema.createTable(TableName.AuditLogStream, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("url").notNullable();
|
||||
t.text("encryptedHeadersCiphertext");
|
||||
t.text("encryptedHeadersIV");
|
||||
t.text("encryptedHeadersTag");
|
||||
t.string("encryptedHeadersAlgorithm");
|
||||
t.string("encryptedHeadersKeyEncoding");
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.AuditLogStream);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await dropOnUpdateTrigger(knex, TableName.AuditLogStream);
|
||||
await knex.schema.dropTableIfExists(TableName.AuditLogStream);
|
||||
}
|
25
backend/src/db/schemas/audit-log-streams.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const AuditLogStreamsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
url: z.string(),
|
||||
encryptedHeadersCiphertext: z.string().nullable().optional(),
|
||||
encryptedHeadersIV: z.string().nullable().optional(),
|
||||
encryptedHeadersTag: z.string().nullable().optional(),
|
||||
encryptedHeadersAlgorithm: z.string().nullable().optional(),
|
||||
encryptedHeadersKeyEncoding: z.string().nullable().optional(),
|
||||
orgId: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export type TAuditLogStreams = z.infer<typeof AuditLogStreamsSchema>;
|
||||
export type TAuditLogStreamsInsert = Omit<z.input<typeof AuditLogStreamsSchema>, TImmutableDBKeys>;
|
||||
export type TAuditLogStreamsUpdate = Partial<Omit<z.input<typeof AuditLogStreamsSchema>, TImmutableDBKeys>>;
|
@@ -1,4 +1,5 @@
|
||||
export * from "./api-keys";
|
||||
export * from "./audit-log-streams";
|
||||
export * from "./audit-logs";
|
||||
export * from "./auth-token-sessions";
|
||||
export * from "./auth-tokens";
|
||||
|
@@ -62,6 +62,7 @@ export enum TableName {
|
||||
LdapConfig = "ldap_configs",
|
||||
LdapGroupMap = "ldap_group_maps",
|
||||
AuditLog = "audit_logs",
|
||||
AuditLogStream = "audit_log_streams",
|
||||
GitAppInstallSession = "git_app_install_sessions",
|
||||
GitAppOrg = "git_app_org",
|
||||
SecretScanningGitRisk = "secret_scanning_git_risks",
|
||||
|
215
backend/src/ee/routes/v1/audit-log-stream-router.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { AUDIT_LOG_STREAMS } from "@app/lib/api-docs";
|
||||
import { readLimit } from "@app/server/config/rateLimiter";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { SanitizedAuditLogStreamSchema } from "@app/server/routes/sanitizedSchemas";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
export const registerAuditLogStreamRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
description: "Create an Audit Log Stream.",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
body: z.object({
|
||||
url: z.string().min(1).describe(AUDIT_LOG_STREAMS.CREATE.url),
|
||||
headers: z
|
||||
.object({
|
||||
key: z.string().min(1).trim().describe(AUDIT_LOG_STREAMS.CREATE.headers.key),
|
||||
value: z.string().min(1).trim().describe(AUDIT_LOG_STREAMS.CREATE.headers.value)
|
||||
})
|
||||
.describe(AUDIT_LOG_STREAMS.CREATE.headers.desc)
|
||||
.array()
|
||||
.optional()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
auditLogStream: SanitizedAuditLogStreamSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const auditLogStream = await server.services.auditLogStream.create({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
url: req.body.url,
|
||||
headers: req.body.headers
|
||||
});
|
||||
|
||||
return { auditLogStream };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "PATCH",
|
||||
url: "/:id",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
description: "Update an Audit Log Stream by ID.",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
id: z.string().describe(AUDIT_LOG_STREAMS.UPDATE.id)
|
||||
}),
|
||||
body: z.object({
|
||||
url: z.string().optional().describe(AUDIT_LOG_STREAMS.UPDATE.url),
|
||||
headers: z
|
||||
.object({
|
||||
key: z.string().min(1).trim().describe(AUDIT_LOG_STREAMS.UPDATE.headers.key),
|
||||
value: z.string().min(1).trim().describe(AUDIT_LOG_STREAMS.UPDATE.headers.value)
|
||||
})
|
||||
.describe(AUDIT_LOG_STREAMS.UPDATE.headers.desc)
|
||||
.array()
|
||||
.optional()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
auditLogStream: SanitizedAuditLogStreamSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const auditLogStream = await server.services.auditLogStream.updateById({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
id: req.params.id,
|
||||
url: req.body.url,
|
||||
headers: req.body.headers
|
||||
});
|
||||
|
||||
return { auditLogStream };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "DELETE",
|
||||
url: "/:id",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
description: "Delete an Audit Log Stream by ID.",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
id: z.string().describe(AUDIT_LOG_STREAMS.DELETE.id)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
auditLogStream: SanitizedAuditLogStreamSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const auditLogStream = await server.services.auditLogStream.deleteById({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
id: req.params.id
|
||||
});
|
||||
|
||||
return { auditLogStream };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/:id",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
description: "Get an Audit Log Stream by ID.",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
id: z.string().describe(AUDIT_LOG_STREAMS.GET_BY_ID.id)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
auditLogStream: SanitizedAuditLogStreamSchema.extend({
|
||||
headers: z
|
||||
.object({
|
||||
key: z.string(),
|
||||
value: z.string()
|
||||
})
|
||||
.array()
|
||||
.optional()
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const auditLogStream = await server.services.auditLogStream.getById({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
id: req.params.id
|
||||
});
|
||||
|
||||
return { auditLogStream };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
description: "List Audit Log Streams.",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
response: {
|
||||
200: z.object({
|
||||
auditLogStreams: SanitizedAuditLogStreamSchema.array()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const auditLogStreams = await server.services.auditLogStream.list({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
actorAuthMethod: req.permission.authMethod
|
||||
});
|
||||
|
||||
return { auditLogStreams };
|
||||
}
|
||||
});
|
||||
};
|
@@ -1,3 +1,4 @@
|
||||
import { registerAuditLogStreamRouter } from "./audit-log-stream-router";
|
||||
import { registerDynamicSecretLeaseRouter } from "./dynamic-secret-lease-router";
|
||||
import { registerDynamicSecretRouter } from "./dynamic-secret-router";
|
||||
import { registerGroupRouter } from "./group-router";
|
||||
@@ -55,6 +56,7 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
||||
await server.register(registerSecretRotationRouter, { prefix: "/secret-rotations" });
|
||||
await server.register(registerSecretVersionRouter, { prefix: "/secret" });
|
||||
await server.register(registerGroupRouter, { prefix: "/groups" });
|
||||
await server.register(registerAuditLogStreamRouter, { prefix: "/audit-log-streams" });
|
||||
await server.register(
|
||||
async (privilegeRouter) => {
|
||||
await privilegeRouter.register(registerUserAdditionalPrivilegeRouter, { prefix: "/users" });
|
||||
|
@@ -0,0 +1,11 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TAuditLogStreamDALFactory = ReturnType<typeof auditLogStreamDALFactory>;
|
||||
|
||||
export const auditLogStreamDALFactory = (db: TDbClient) => {
|
||||
const orm = ormify(db, TableName.AuditLogStream);
|
||||
|
||||
return orm;
|
||||
};
|
@@ -0,0 +1,233 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import { RawAxiosRequestHeaders } from "axios";
|
||||
|
||||
import { SecretKeyEncoding } from "@app/db/schemas";
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { validateLocalIps } from "@app/lib/validator";
|
||||
|
||||
import { AUDIT_LOG_STREAM_TIMEOUT } from "../audit-log/audit-log-queue";
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||
import { TAuditLogStreamDALFactory } from "./audit-log-stream-dal";
|
||||
import {
|
||||
LogStreamHeaders,
|
||||
TCreateAuditLogStreamDTO,
|
||||
TDeleteAuditLogStreamDTO,
|
||||
TGetDetailsAuditLogStreamDTO,
|
||||
TListAuditLogStreamDTO,
|
||||
TUpdateAuditLogStreamDTO
|
||||
} from "./audit-log-stream-types";
|
||||
|
||||
type TAuditLogStreamServiceFactoryDep = {
|
||||
auditLogStreamDAL: TAuditLogStreamDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
export type TAuditLogStreamServiceFactory = ReturnType<typeof auditLogStreamServiceFactory>;
|
||||
|
||||
export const auditLogStreamServiceFactory = ({
|
||||
auditLogStreamDAL,
|
||||
permissionService,
|
||||
licenseService
|
||||
}: TAuditLogStreamServiceFactoryDep) => {
|
||||
const create = async ({
|
||||
url,
|
||||
actor,
|
||||
headers = [],
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod
|
||||
}: TCreateAuditLogStreamDTO) => {
|
||||
if (!actorOrgId) throw new BadRequestError({ message: "Missing org id from token" });
|
||||
|
||||
const plan = await licenseService.getPlan(actorOrgId);
|
||||
if (!plan.auditLogStreams)
|
||||
throw new BadRequestError({
|
||||
message: "Failed to create audit log streams due to plan restriction. Upgrade plan to create group."
|
||||
});
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Settings);
|
||||
|
||||
validateLocalIps(url);
|
||||
|
||||
const totalStreams = await auditLogStreamDAL.find({ orgId: actorOrgId });
|
||||
if (totalStreams.length >= plan.auditLogStreamLimit) {
|
||||
throw new BadRequestError({
|
||||
message:
|
||||
"Failed to create audit log streams due to plan limit reached. Kindly contact Infisical to add more streams."
|
||||
});
|
||||
}
|
||||
|
||||
// testing connection first
|
||||
const streamHeaders: RawAxiosRequestHeaders = { "Content-Type": "application/json" };
|
||||
if (headers.length)
|
||||
headers.forEach(({ key, value }) => {
|
||||
streamHeaders[key] = value;
|
||||
});
|
||||
await request
|
||||
.post(
|
||||
url,
|
||||
{ ping: "ok" },
|
||||
{
|
||||
headers: streamHeaders,
|
||||
// request timeout
|
||||
timeout: AUDIT_LOG_STREAM_TIMEOUT,
|
||||
// connection timeout
|
||||
signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
throw new Error(`Failed to connect with the source ${(err as Error)?.message}`);
|
||||
});
|
||||
const encryptedHeaders = headers ? infisicalSymmetricEncypt(JSON.stringify(headers)) : undefined;
|
||||
const logStream = await auditLogStreamDAL.create({
|
||||
orgId: actorOrgId,
|
||||
url,
|
||||
...(encryptedHeaders
|
||||
? {
|
||||
encryptedHeadersCiphertext: encryptedHeaders.ciphertext,
|
||||
encryptedHeadersIV: encryptedHeaders.iv,
|
||||
encryptedHeadersTag: encryptedHeaders.tag,
|
||||
encryptedHeadersAlgorithm: encryptedHeaders.algorithm,
|
||||
encryptedHeadersKeyEncoding: encryptedHeaders.encoding
|
||||
}
|
||||
: {})
|
||||
});
|
||||
return logStream;
|
||||
};
|
||||
|
||||
const updateById = async ({
|
||||
id,
|
||||
url,
|
||||
actor,
|
||||
headers = [],
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod
|
||||
}: TUpdateAuditLogStreamDTO) => {
|
||||
if (!actorOrgId) throw new BadRequestError({ message: "Missing org id from token" });
|
||||
|
||||
const plan = await licenseService.getPlan(actorOrgId);
|
||||
if (!plan.auditLogStreams)
|
||||
throw new BadRequestError({
|
||||
message: "Failed to update audit log streams due to plan restriction. Upgrade plan to create group."
|
||||
});
|
||||
|
||||
const logStream = await auditLogStreamDAL.findById(id);
|
||||
if (!logStream) throw new BadRequestError({ message: "Audit log stream not found" });
|
||||
|
||||
const { orgId } = logStream;
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||
|
||||
if (url) validateLocalIps(url);
|
||||
|
||||
// testing connection first
|
||||
const streamHeaders: RawAxiosRequestHeaders = { "Content-Type": "application/json" };
|
||||
if (headers.length)
|
||||
headers.forEach(({ key, value }) => {
|
||||
streamHeaders[key] = value;
|
||||
});
|
||||
|
||||
await request
|
||||
.post(
|
||||
url || logStream.url,
|
||||
{ ping: "ok" },
|
||||
{
|
||||
headers: streamHeaders,
|
||||
// request timeout
|
||||
timeout: AUDIT_LOG_STREAM_TIMEOUT,
|
||||
// connection timeout
|
||||
signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
throw new Error(`Failed to connect with the source ${(err as Error)?.message}`);
|
||||
});
|
||||
|
||||
const encryptedHeaders = headers ? infisicalSymmetricEncypt(JSON.stringify(headers)) : undefined;
|
||||
const updatedLogStream = await auditLogStreamDAL.updateById(id, {
|
||||
url,
|
||||
...(encryptedHeaders
|
||||
? {
|
||||
encryptedHeadersCiphertext: encryptedHeaders.ciphertext,
|
||||
encryptedHeadersIV: encryptedHeaders.iv,
|
||||
encryptedHeadersTag: encryptedHeaders.tag,
|
||||
encryptedHeadersAlgorithm: encryptedHeaders.algorithm,
|
||||
encryptedHeadersKeyEncoding: encryptedHeaders.encoding
|
||||
}
|
||||
: {})
|
||||
});
|
||||
return updatedLogStream;
|
||||
};
|
||||
|
||||
const deleteById = async ({ id, actor, actorId, actorOrgId, actorAuthMethod }: TDeleteAuditLogStreamDTO) => {
|
||||
if (!actorOrgId) throw new BadRequestError({ message: "Missing org id from token" });
|
||||
|
||||
const logStream = await auditLogStreamDAL.findById(id);
|
||||
if (!logStream) throw new BadRequestError({ message: "Audit log stream not found" });
|
||||
|
||||
const { orgId } = logStream;
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Settings);
|
||||
|
||||
const deletedLogStream = await auditLogStreamDAL.deleteById(id);
|
||||
return deletedLogStream;
|
||||
};
|
||||
|
||||
const getById = async ({ id, actor, actorId, actorOrgId, actorAuthMethod }: TGetDetailsAuditLogStreamDTO) => {
|
||||
const logStream = await auditLogStreamDAL.findById(id);
|
||||
if (!logStream) throw new BadRequestError({ message: "Audit log stream not found" });
|
||||
|
||||
const { orgId } = logStream;
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
||||
|
||||
const headers =
|
||||
logStream?.encryptedHeadersCiphertext && logStream?.encryptedHeadersIV && logStream?.encryptedHeadersTag
|
||||
? (JSON.parse(
|
||||
infisicalSymmetricDecrypt({
|
||||
tag: logStream.encryptedHeadersTag,
|
||||
iv: logStream.encryptedHeadersIV,
|
||||
ciphertext: logStream.encryptedHeadersCiphertext,
|
||||
keyEncoding: logStream.encryptedHeadersKeyEncoding as SecretKeyEncoding
|
||||
})
|
||||
) as LogStreamHeaders[])
|
||||
: undefined;
|
||||
|
||||
return { ...logStream, headers };
|
||||
};
|
||||
|
||||
const list = async ({ actor, actorId, actorOrgId, actorAuthMethod }: TListAuditLogStreamDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
||||
|
||||
const logStreams = await auditLogStreamDAL.find({ orgId: actorOrgId });
|
||||
return logStreams;
|
||||
};
|
||||
|
||||
return {
|
||||
create,
|
||||
updateById,
|
||||
deleteById,
|
||||
getById,
|
||||
list
|
||||
};
|
||||
};
|
@@ -0,0 +1,27 @@
|
||||
import { TOrgPermission } from "@app/lib/types";
|
||||
|
||||
export type LogStreamHeaders = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TCreateAuditLogStreamDTO = Omit<TOrgPermission, "orgId"> & {
|
||||
url: string;
|
||||
headers?: LogStreamHeaders[];
|
||||
};
|
||||
|
||||
export type TUpdateAuditLogStreamDTO = Omit<TOrgPermission, "orgId"> & {
|
||||
id: string;
|
||||
url?: string;
|
||||
headers?: LogStreamHeaders[];
|
||||
};
|
||||
|
||||
export type TDeleteAuditLogStreamDTO = Omit<TOrgPermission, "orgId"> & {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type TListAuditLogStreamDTO = Omit<TOrgPermission, "orgId">;
|
||||
|
||||
export type TGetDetailsAuditLogStreamDTO = Omit<TOrgPermission, "orgId"> & {
|
||||
id: string;
|
||||
};
|
@@ -1,13 +1,21 @@
|
||||
import { RawAxiosRequestHeaders } from "axios";
|
||||
|
||||
import { SecretKeyEncoding } from "@app/db/schemas";
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
|
||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||
|
||||
import { TAuditLogStreamDALFactory } from "../audit-log-stream/audit-log-stream-dal";
|
||||
import { LogStreamHeaders } from "../audit-log-stream/audit-log-stream-types";
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { TAuditLogDALFactory } from "./audit-log-dal";
|
||||
import { TCreateAuditLogDTO } from "./audit-log-types";
|
||||
|
||||
type TAuditLogQueueServiceFactoryDep = {
|
||||
auditLogDAL: TAuditLogDALFactory;
|
||||
auditLogStreamDAL: Pick<TAuditLogStreamDALFactory, "find">;
|
||||
queueService: TQueueServiceFactory;
|
||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
@@ -15,11 +23,15 @@ type TAuditLogQueueServiceFactoryDep = {
|
||||
|
||||
export type TAuditLogQueueServiceFactory = ReturnType<typeof auditLogQueueServiceFactory>;
|
||||
|
||||
// keep this timeout 5s it must be fast because else the queue will take time to finish
|
||||
// audit log is a crowded queue thus needs to be fast
|
||||
export const AUDIT_LOG_STREAM_TIMEOUT = 5 * 1000;
|
||||
export const auditLogQueueServiceFactory = ({
|
||||
auditLogDAL,
|
||||
queueService,
|
||||
projectDAL,
|
||||
licenseService
|
||||
licenseService,
|
||||
auditLogStreamDAL
|
||||
}: TAuditLogQueueServiceFactoryDep) => {
|
||||
const pushToLog = async (data: TCreateAuditLogDTO) => {
|
||||
await queueService.queue(QueueName.AuditLog, QueueJobs.AuditLog, data, {
|
||||
@@ -47,7 +59,7 @@ export const auditLogQueueServiceFactory = ({
|
||||
// skip inserting if audit log retention is 0 meaning its not supported
|
||||
if (ttl === 0) return;
|
||||
|
||||
await auditLogDAL.create({
|
||||
const auditLog = await auditLogDAL.create({
|
||||
actor: actor.type,
|
||||
actorMetadata: actor.metadata,
|
||||
userAgent,
|
||||
@@ -59,6 +71,46 @@ export const auditLogQueueServiceFactory = ({
|
||||
eventMetadata: event.metadata,
|
||||
userAgentType
|
||||
});
|
||||
|
||||
const logStreams = orgId ? await auditLogStreamDAL.find({ orgId }) : [];
|
||||
await Promise.allSettled(
|
||||
logStreams.map(
|
||||
async ({
|
||||
url,
|
||||
encryptedHeadersTag,
|
||||
encryptedHeadersIV,
|
||||
encryptedHeadersKeyEncoding,
|
||||
encryptedHeadersCiphertext
|
||||
}) => {
|
||||
const streamHeaders =
|
||||
encryptedHeadersIV && encryptedHeadersCiphertext && encryptedHeadersTag
|
||||
? (JSON.parse(
|
||||
infisicalSymmetricDecrypt({
|
||||
keyEncoding: encryptedHeadersKeyEncoding as SecretKeyEncoding,
|
||||
iv: encryptedHeadersIV,
|
||||
tag: encryptedHeadersTag,
|
||||
ciphertext: encryptedHeadersCiphertext
|
||||
})
|
||||
) as LogStreamHeaders[])
|
||||
: [];
|
||||
|
||||
const headers: RawAxiosRequestHeaders = { "Content-Type": "application/json" };
|
||||
|
||||
if (streamHeaders.length)
|
||||
streamHeaders.forEach(({ key, value }) => {
|
||||
headers[key] = value;
|
||||
});
|
||||
|
||||
return request.post(url, auditLog, {
|
||||
headers,
|
||||
// request timeout
|
||||
timeout: AUDIT_LOG_STREAM_TIMEOUT,
|
||||
// connection timeout
|
||||
signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
queueService.start(QueueName.AuditLogPrune, async () => {
|
||||
|
194
backend/src/ee/services/dynamic-secret/providers/aws-iam.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
import {
|
||||
AddUserToGroupCommand,
|
||||
AttachUserPolicyCommand,
|
||||
CreateAccessKeyCommand,
|
||||
CreateUserCommand,
|
||||
DeleteAccessKeyCommand,
|
||||
DeleteUserCommand,
|
||||
DeleteUserPolicyCommand,
|
||||
DetachUserPolicyCommand,
|
||||
GetUserCommand,
|
||||
IAMClient,
|
||||
ListAccessKeysCommand,
|
||||
ListAttachedUserPoliciesCommand,
|
||||
ListGroupsForUserCommand,
|
||||
ListUserPoliciesCommand,
|
||||
PutUserPolicyCommand,
|
||||
RemoveUserFromGroupCommand
|
||||
} from "@aws-sdk/client-iam";
|
||||
import { z } from "zod";
|
||||
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
|
||||
import { DynamicSecretAwsIamSchema, TDynamicProviderFns } from "./models";
|
||||
|
||||
const generateUsername = () => {
|
||||
return alphaNumericNanoId(32);
|
||||
};
|
||||
|
||||
export const AwsIamProvider = (): TDynamicProviderFns => {
|
||||
const validateProviderInputs = async (inputs: unknown) => {
|
||||
const providerInputs = await DynamicSecretAwsIamSchema.parseAsync(inputs);
|
||||
return providerInputs;
|
||||
};
|
||||
|
||||
const getClient = async (providerInputs: z.infer<typeof DynamicSecretAwsIamSchema>) => {
|
||||
const client = new IAMClient({
|
||||
region: providerInputs.region,
|
||||
credentials: {
|
||||
accessKeyId: providerInputs.accessKey,
|
||||
secretAccessKey: providerInputs.secretAccessKey
|
||||
}
|
||||
});
|
||||
|
||||
return client;
|
||||
};
|
||||
|
||||
const validateConnection = async (inputs: unknown) => {
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await getClient(providerInputs);
|
||||
|
||||
const isConnected = await client.send(new GetUserCommand({})).then(() => true);
|
||||
return isConnected;
|
||||
};
|
||||
|
||||
const create = async (inputs: unknown) => {
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await getClient(providerInputs);
|
||||
|
||||
const username = generateUsername();
|
||||
const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs;
|
||||
const createUserRes = await client.send(
|
||||
new CreateUserCommand({
|
||||
Path: awsPath,
|
||||
PermissionsBoundary: permissionBoundaryPolicyArn || undefined,
|
||||
Tags: [{ Key: "createdBy", Value: "infisical-dynamic-secret" }],
|
||||
UserName: username
|
||||
})
|
||||
);
|
||||
if (!createUserRes.User) throw new BadRequestError({ message: "Failed to create AWS IAM User" });
|
||||
if (userGroups) {
|
||||
await Promise.all(
|
||||
userGroups
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((group) =>
|
||||
client.send(new AddUserToGroupCommand({ UserName: createUserRes?.User?.UserName, GroupName: group }))
|
||||
)
|
||||
);
|
||||
}
|
||||
if (policyArns) {
|
||||
await Promise.all(
|
||||
policyArns
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((policyArn) =>
|
||||
client.send(new AttachUserPolicyCommand({ UserName: createUserRes?.User?.UserName, PolicyArn: policyArn }))
|
||||
)
|
||||
);
|
||||
}
|
||||
if (policyDocument) {
|
||||
await client.send(
|
||||
new PutUserPolicyCommand({
|
||||
UserName: createUserRes.User.UserName,
|
||||
PolicyName: `infisical-dynamic-policy-${alphaNumericNanoId(4)}`,
|
||||
PolicyDocument: policyDocument
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const createAccessKeyRes = await client.send(
|
||||
new CreateAccessKeyCommand({
|
||||
UserName: createUserRes.User.UserName
|
||||
})
|
||||
);
|
||||
if (!createAccessKeyRes.AccessKey)
|
||||
throw new BadRequestError({ message: "Failed to create AWS IAM User access key" });
|
||||
|
||||
return {
|
||||
entityId: username,
|
||||
data: {
|
||||
ACCESS_KEY: createAccessKeyRes.AccessKey.AccessKeyId,
|
||||
SECRET_ACCESS_KEY: createAccessKeyRes.AccessKey.SecretAccessKey,
|
||||
USERNAME: username
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const revoke = async (inputs: unknown, entityId: string) => {
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await getClient(providerInputs);
|
||||
|
||||
const username = entityId;
|
||||
|
||||
// remove user from groups
|
||||
const userGroups = await client.send(new ListGroupsForUserCommand({ UserName: username }));
|
||||
await Promise.all(
|
||||
(userGroups.Groups || []).map(({ GroupName }) =>
|
||||
client.send(
|
||||
new RemoveUserFromGroupCommand({
|
||||
GroupName,
|
||||
UserName: username
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// remove user access keys
|
||||
const userAccessKeys = await client.send(new ListAccessKeysCommand({ UserName: username }));
|
||||
await Promise.all(
|
||||
(userAccessKeys.AccessKeyMetadata || []).map(({ AccessKeyId }) =>
|
||||
client.send(
|
||||
new DeleteAccessKeyCommand({
|
||||
AccessKeyId,
|
||||
UserName: username
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// remove user inline policies
|
||||
const userInlinePolicies = await client.send(new ListUserPoliciesCommand({ UserName: username }));
|
||||
await Promise.all(
|
||||
(userInlinePolicies.PolicyNames || []).map((policyName) =>
|
||||
client.send(
|
||||
new DeleteUserPolicyCommand({
|
||||
PolicyName: policyName,
|
||||
UserName: username
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// remove user attached policies
|
||||
const userAttachedPolicies = await client.send(new ListAttachedUserPoliciesCommand({ UserName: username }));
|
||||
await Promise.all(
|
||||
(userAttachedPolicies.AttachedPolicies || []).map((policy) =>
|
||||
client.send(
|
||||
new DetachUserPolicyCommand({
|
||||
PolicyArn: policy.PolicyArn,
|
||||
UserName: username
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await client.send(new DeleteUserCommand({ UserName: username }));
|
||||
return { entityId: username };
|
||||
};
|
||||
|
||||
const renew = async (_inputs: unknown, entityId: string) => {
|
||||
// do nothing
|
||||
const username = entityId;
|
||||
return { entityId: username };
|
||||
};
|
||||
|
||||
return {
|
||||
validateProviderInputs,
|
||||
validateConnection,
|
||||
create,
|
||||
revoke,
|
||||
renew
|
||||
};
|
||||
};
|
@@ -1,8 +1,10 @@
|
||||
import { AwsIamProvider } from "./aws-iam";
|
||||
import { CassandraProvider } from "./cassandra";
|
||||
import { DynamicSecretProviders } from "./models";
|
||||
import { SqlDatabaseProvider } from "./sql-database";
|
||||
|
||||
export const buildDynamicSecretProviders = () => ({
|
||||
[DynamicSecretProviders.SqlDatabase]: SqlDatabaseProvider(),
|
||||
[DynamicSecretProviders.Cassandra]: CassandraProvider()
|
||||
[DynamicSecretProviders.Cassandra]: CassandraProvider(),
|
||||
[DynamicSecretProviders.AwsIam]: AwsIamProvider()
|
||||
});
|
||||
|
@@ -8,38 +8,51 @@ export enum SqlProviders {
|
||||
|
||||
export const DynamicSecretSqlDBSchema = z.object({
|
||||
client: z.nativeEnum(SqlProviders),
|
||||
host: z.string().toLowerCase(),
|
||||
host: z.string().trim().toLowerCase(),
|
||||
port: z.number(),
|
||||
database: z.string(),
|
||||
username: z.string(),
|
||||
password: z.string(),
|
||||
creationStatement: z.string(),
|
||||
revocationStatement: z.string(),
|
||||
renewStatement: z.string().optional(),
|
||||
database: z.string().trim(),
|
||||
username: z.string().trim(),
|
||||
password: z.string().trim(),
|
||||
creationStatement: z.string().trim(),
|
||||
revocationStatement: z.string().trim(),
|
||||
renewStatement: z.string().trim().optional(),
|
||||
ca: z.string().optional()
|
||||
});
|
||||
|
||||
export const DynamicSecretCassandraSchema = z.object({
|
||||
host: z.string().toLowerCase(),
|
||||
host: z.string().trim().toLowerCase(),
|
||||
port: z.number(),
|
||||
localDataCenter: z.string().min(1),
|
||||
keyspace: z.string().optional(),
|
||||
username: z.string(),
|
||||
password: z.string(),
|
||||
creationStatement: z.string(),
|
||||
revocationStatement: z.string(),
|
||||
renewStatement: z.string().optional(),
|
||||
localDataCenter: z.string().trim().min(1),
|
||||
keyspace: z.string().trim().optional(),
|
||||
username: z.string().trim(),
|
||||
password: z.string().trim(),
|
||||
creationStatement: z.string().trim(),
|
||||
revocationStatement: z.string().trim(),
|
||||
renewStatement: z.string().trim().optional(),
|
||||
ca: z.string().optional()
|
||||
});
|
||||
|
||||
export const DynamicSecretAwsIamSchema = z.object({
|
||||
accessKey: z.string().trim().min(1),
|
||||
secretAccessKey: z.string().trim().min(1),
|
||||
region: z.string().trim().min(1),
|
||||
awsPath: z.string().trim().optional(),
|
||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||
policyDocument: z.string().trim().optional(),
|
||||
userGroups: z.string().trim().optional(),
|
||||
policyArns: z.string().trim().optional()
|
||||
});
|
||||
|
||||
export enum DynamicSecretProviders {
|
||||
SqlDatabase = "sql-database",
|
||||
Cassandra = "cassandra"
|
||||
Cassandra = "cassandra",
|
||||
AwsIam = "aws-iam"
|
||||
}
|
||||
|
||||
export const DynamicSecretProviderSchema = z.discriminatedUnion("type", [
|
||||
z.object({ type: z.literal(DynamicSecretProviders.SqlDatabase), inputs: DynamicSecretSqlDBSchema }),
|
||||
z.object({ type: z.literal(DynamicSecretProviders.Cassandra), inputs: DynamicSecretCassandraSchema })
|
||||
z.object({ type: z.literal(DynamicSecretProviders.Cassandra), inputs: DynamicSecretCassandraSchema }),
|
||||
z.object({ type: z.literal(DynamicSecretProviders.AwsIam), inputs: DynamicSecretAwsIamSchema })
|
||||
]);
|
||||
|
||||
export type TDynamicProviderFns = {
|
||||
|
@@ -24,6 +24,8 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
customAlerts: false,
|
||||
auditLogs: false,
|
||||
auditLogsRetentionDays: 0,
|
||||
auditLogStreams: false,
|
||||
auditLogStreamLimit: 3,
|
||||
samlSSO: false,
|
||||
scim: false,
|
||||
ldap: false,
|
||||
|
@@ -40,6 +40,8 @@ export type TFeatureSet = {
|
||||
customAlerts: false;
|
||||
auditLogs: false;
|
||||
auditLogsRetentionDays: 0;
|
||||
auditLogStreams: false;
|
||||
auditLogStreamLimit: 3;
|
||||
samlSSO: false;
|
||||
scim: false;
|
||||
ldap: false;
|
||||
|
@@ -614,3 +614,29 @@ export const INTEGRATION = {
|
||||
integrationId: "The ID of the integration object."
|
||||
}
|
||||
};
|
||||
|
||||
export const AUDIT_LOG_STREAMS = {
|
||||
CREATE: {
|
||||
url: "The HTTP URL to push logs to.",
|
||||
headers: {
|
||||
desc: "The HTTP headers attached for the external prrovider requests.",
|
||||
key: "The HTTP header key name.",
|
||||
value: "The HTTP header value."
|
||||
}
|
||||
},
|
||||
UPDATE: {
|
||||
id: "The ID of the audit log stream to update.",
|
||||
url: "The HTTP URL to push logs to.",
|
||||
headers: {
|
||||
desc: "The HTTP headers attached for the external prrovider requests.",
|
||||
key: "The HTTP header key name.",
|
||||
value: "The HTTP header value."
|
||||
}
|
||||
},
|
||||
DELETE: {
|
||||
id: "The ID of the audit log stream to delete."
|
||||
},
|
||||
GET_BY_ID: {
|
||||
id: "The ID of the audit log stream to get details."
|
||||
}
|
||||
};
|
||||
|
@@ -119,6 +119,7 @@ const envSchema = z
|
||||
})
|
||||
.transform((data) => ({
|
||||
...data,
|
||||
isCloud: Boolean(data.LICENSE_SERVER_KEY),
|
||||
isSmtpConfigured: Boolean(data.SMTP_HOST),
|
||||
isRedisConfigured: Boolean(data.REDIS_URL),
|
||||
isDevelopmentMode: data.NODE_ENV === "development",
|
||||
|
@@ -17,7 +17,7 @@ export type TOrgPermission = {
|
||||
actorId: string;
|
||||
orgId: string;
|
||||
actorAuthMethod: ActorAuthMethod;
|
||||
actorOrgId: string | undefined;
|
||||
actorOrgId: string;
|
||||
};
|
||||
|
||||
export type TProjectPermission = {
|
||||
|
@@ -1 +1,2 @@
|
||||
export { isDisposableEmail } from "./validate-email";
|
||||
export { validateLocalIps } from "./validate-url";
|
||||
|
18
backend/src/lib/validator/validate-url.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { getConfig } from "../config/env";
|
||||
import { BadRequestError } from "../errors";
|
||||
|
||||
export const validateLocalIps = (url: string) => {
|
||||
const validUrl = new URL(url);
|
||||
const appCfg = getConfig();
|
||||
// on cloud local ips are not allowed
|
||||
if (
|
||||
appCfg.isCloud &&
|
||||
(validUrl.host === "host.docker.internal" ||
|
||||
validUrl.host.match(/^10\.\d+\.\d+\.\d+/) ||
|
||||
validUrl.host.match(/^192\.168\.\d+\.\d+/))
|
||||
)
|
||||
throw new BadRequestError({ message: "Local IPs not allowed as URL" });
|
||||
|
||||
if (validUrl.host === "localhost" || validUrl.host === "127.0.0.1")
|
||||
throw new BadRequestError({ message: "Localhost not allowed" });
|
||||
};
|
@@ -36,7 +36,7 @@ export const writeLimit: RateLimitOptions = {
|
||||
export const secretsLimit: RateLimitOptions = {
|
||||
// secrets, folders, secret imports
|
||||
timeWindow: 60 * 1000,
|
||||
max: 600,
|
||||
max: 1000,
|
||||
keyGenerator: (req) => req.realIp
|
||||
};
|
||||
|
||||
|
@@ -5,6 +5,8 @@ import { registerV1EERoutes } from "@app/ee/routes/v1";
|
||||
import { auditLogDALFactory } from "@app/ee/services/audit-log/audit-log-dal";
|
||||
import { auditLogQueueServiceFactory } from "@app/ee/services/audit-log/audit-log-queue";
|
||||
import { auditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
||||
import { auditLogStreamDALFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-dal";
|
||||
import { auditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
|
||||
import { dynamicSecretDALFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-dal";
|
||||
import { dynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
|
||||
import { buildDynamicSecretProviders } from "@app/ee/services/dynamic-secret/providers";
|
||||
@@ -193,6 +195,7 @@ export const registerRoutes = async (
|
||||
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
|
||||
|
||||
const auditLogDAL = auditLogDALFactory(db);
|
||||
const auditLogStreamDAL = auditLogStreamDALFactory(db);
|
||||
const trustedIpDAL = trustedIpDALFactory(db);
|
||||
const telemetryDAL = telemetryDALFactory(db);
|
||||
|
||||
@@ -243,9 +246,15 @@ export const registerRoutes = async (
|
||||
auditLogDAL,
|
||||
queueService,
|
||||
projectDAL,
|
||||
licenseService
|
||||
licenseService,
|
||||
auditLogStreamDAL
|
||||
});
|
||||
const auditLogService = auditLogServiceFactory({ auditLogDAL, permissionService, auditLogQueue });
|
||||
const auditLogStreamService = auditLogStreamServiceFactory({
|
||||
licenseService,
|
||||
permissionService,
|
||||
auditLogStreamDAL
|
||||
});
|
||||
const sapService = secretApprovalPolicyServiceFactory({
|
||||
projectMembershipDAL,
|
||||
projectEnvDAL,
|
||||
@@ -715,6 +724,7 @@ export const registerRoutes = async (
|
||||
saml: samlService,
|
||||
ldap: ldapService,
|
||||
auditLog: auditLogService,
|
||||
auditLogStream: auditLogStreamService,
|
||||
secretScanning: secretScanningService,
|
||||
license: licenseService,
|
||||
trustedIp: trustedIpService,
|
||||
|
@@ -69,3 +69,10 @@ export const SanitizedDynamicSecretSchema = DynamicSecretsSchema.omit({
|
||||
keyEncoding: true,
|
||||
algorithm: true
|
||||
});
|
||||
|
||||
export const SanitizedAuditLogStreamSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
@@ -76,6 +76,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
slug: z.string(),
|
||||
organization: z.string(),
|
||||
environments: z
|
||||
.object({
|
||||
|
@@ -82,7 +82,7 @@ export const authSignupServiceFactory = ({
|
||||
await smtpService.sendMail({
|
||||
template: SmtpTemplates.EmailVerification,
|
||||
subjectLine: "Infisical confirmation code",
|
||||
recipients: [email],
|
||||
recipients: [user.email as string],
|
||||
substitutions: {
|
||||
code: token
|
||||
}
|
||||
|
@@ -566,20 +566,32 @@ export const integrationAuthServiceFactory = ({
|
||||
}
|
||||
});
|
||||
const kms = new AWS.KMS();
|
||||
|
||||
const aliases = await kms.listAliases({}).promise();
|
||||
const keys = await kms.listKeys({}).promise();
|
||||
const response = keys
|
||||
.Keys!.map((key) => {
|
||||
const keyAlias = aliases.Aliases!.find((alias) => key.KeyId === alias.TargetKeyId);
|
||||
if (!keyAlias?.AliasName?.includes("alias/aws/") || keyAlias?.AliasName?.includes("alias/aws/secretsmanager")) {
|
||||
return { id: String(key.KeyId), alias: String(keyAlias?.AliasName || key.KeyId) };
|
||||
}
|
||||
return { id: "null", alias: "null" };
|
||||
})
|
||||
.filter((elem) => elem.id !== "null");
|
||||
|
||||
return response;
|
||||
const keyAliases = aliases.Aliases!.filter((alias) => {
|
||||
if (!alias.TargetKeyId) return false;
|
||||
|
||||
if (integrationAuth.integration === Integrations.AWS_PARAMETER_STORE && alias.AliasName === "alias/aws/ssm")
|
||||
return true;
|
||||
|
||||
if (
|
||||
integrationAuth.integration === Integrations.AWS_SECRET_MANAGER &&
|
||||
alias.AliasName === "alias/aws/secretsmanager"
|
||||
)
|
||||
return true;
|
||||
|
||||
if (alias.AliasName?.includes("alias/aws/")) return false;
|
||||
return alias.TargetKeyId;
|
||||
});
|
||||
|
||||
const keysWithAliases = keyAliases.map((alias) => {
|
||||
return {
|
||||
id: alias.TargetKeyId!,
|
||||
alias: alias.AliasName!
|
||||
};
|
||||
});
|
||||
|
||||
return keysWithAliases;
|
||||
};
|
||||
|
||||
const getQoveryProjects = async ({
|
||||
|
@@ -477,24 +477,29 @@ const syncSecretsAWSParameterStore = async ({
|
||||
}),
|
||||
{} as Record<string, AWS.SSM.Parameter>
|
||||
);
|
||||
|
||||
// Identify secrets to create
|
||||
await Promise.all(
|
||||
Object.keys(secrets).map(async (key) => {
|
||||
if (!(key in awsParameterStoreSecretsObj)) {
|
||||
// case: secret does not exist in AWS parameter store
|
||||
// -> create secret
|
||||
if (secrets[key].value) {
|
||||
await ssm
|
||||
.putParameter({
|
||||
Name: `${integration.path}${key}`,
|
||||
Type: "SecureString",
|
||||
Value: secrets[key].value,
|
||||
...(metadata.kmsKeyId && { KeyId: metadata.kmsKeyId }),
|
||||
// Overwrite: true,
|
||||
Tags: metadata.secretAWSTag
|
||||
? metadata.secretAWSTag.map((tag: { key: string; value: string }) => ({ Key: tag.key, Value: tag.value }))
|
||||
? metadata.secretAWSTag.map((tag: { key: string; value: string }) => ({
|
||||
Key: tag.key,
|
||||
Value: tag.value
|
||||
}))
|
||||
: []
|
||||
})
|
||||
.promise();
|
||||
}
|
||||
// case: secret exists in AWS parameter store
|
||||
} else if (awsParameterStoreSecretsObj[key].Value !== secrets[key].value) {
|
||||
// case: secret value doesn't match one in AWS parameter store
|
||||
@@ -567,7 +572,6 @@ const syncSecretsAWSSecretManager = async ({
|
||||
if (awsSecretManagerSecret?.SecretString) {
|
||||
awsSecretManagerSecretObj = JSON.parse(awsSecretManagerSecret.SecretString);
|
||||
}
|
||||
|
||||
if (!isEqual(awsSecretManagerSecretObj, secKeyVal)) {
|
||||
await secretsManager.send(
|
||||
new UpdateSecretCommand({
|
||||
@@ -582,7 +586,7 @@ const syncSecretsAWSSecretManager = async ({
|
||||
new CreateSecretCommand({
|
||||
Name: integration.app as string,
|
||||
SecretString: JSON.stringify(secKeyVal),
|
||||
KmsKeyId: metadata.kmsKeyId ? metadata.kmsKeyId : null,
|
||||
...(metadata.kmsKeyId && { KmsKeyId: metadata.kmsKeyId }),
|
||||
Tags: metadata.secretAWSTag
|
||||
? metadata.secretAWSTag.map((tag: { key: string; value: string }) => ({ Key: tag.key, Value: tag.value }))
|
||||
: []
|
||||
|
@@ -318,7 +318,7 @@ export const secretQueueFactory = ({
|
||||
});
|
||||
|
||||
// add the imported secrets to the current folder secrets
|
||||
content = { ...content, ...importedSecrets };
|
||||
content = { ...importedSecrets, ...content };
|
||||
}
|
||||
}
|
||||
|
||||
|
97
company/documentation/getting-started/introduction.mdx
Normal file
@@ -0,0 +1,97 @@
|
||||
---
|
||||
title: "What is Infisical?"
|
||||
sidebarTitle: "What is Infisical?"
|
||||
description: "An Introduction to the Infisical secret management platform."
|
||||
---
|
||||
|
||||
Infisical is an [open-source](https://github.com/infisical/infisical) secret management platform for developers.
|
||||
It provides capabilities for storing, managing, and syncing application configuration and secrets like API keys, database
|
||||
credentials, and certificates across infrastructure. In addition, Infisical prevents secrets leaks to git and enables secure
|
||||
sharing of secrets among engineers.
|
||||
|
||||
Start managing secrets securely with [Infisical Cloud](https://app.infisical.com) or learn how to [host Infisical](/self-hosting/overview) yourself.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Infisical Cloud"
|
||||
href="https://app.infisical.com/signup"
|
||||
icon="cloud"
|
||||
color="#000000"
|
||||
>
|
||||
Get started with Infisical Cloud in just a few minutes.
|
||||
</Card>
|
||||
<Card
|
||||
href="/self-hosting/overview"
|
||||
title="Self-hosting"
|
||||
icon="server"
|
||||
color="#000000"
|
||||
>
|
||||
Self-host Infisical on your own infrastructure.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Why Infisical?
|
||||
|
||||
Infisical helps developers achieve secure centralized secret management and provides all the tools to easily manage secrets in various environments and infrastructure components. In particular, here are some of the most common points that developers mention after adopting Infisical:
|
||||
- Streamlined **local development** processes (switching .env files to [Infisical CLI](/cli/commands/run) and removing secrets from developer machines).
|
||||
- **Best-in-class developer experience** with an easy-to-use [Web Dashboard](/documentation/platform/project).
|
||||
- Simple secret management inside **[CI/CD pipelines](/integrations/cicd/githubactions)** and staging environments.
|
||||
- Secure and compliant secret management practices in **[production environments](/sdks/overview)**.
|
||||
- **Facilitated workflows** around [secret change management](/documentation/platform/pr-workflows), [access requests](/documentation/platform/access-controls/access-requests), [temporary access provisioning](/documentation/platform/access-controls/temporary-access), and more.
|
||||
- **Improved security posture** thanks to [secret scanning](/cli/scanning-overview), [granular access control policies](/documentation/platform/access-controls/overview), [automated secret rotation](https://infisical.com/docs/documentation/platform/secret-rotation/overview), and [dynamic secrets](/documentation/platform/dynamic-secrets/overview) capabilities.
|
||||
|
||||
## How does Infisical work?
|
||||
|
||||
To make secret management effortless and secure, Infisical follows a certain structure for enabling secret management workflows as defined below.
|
||||
|
||||
**Identities** in Infisical are users or machine which have a certain set of roles and permissions assigned to them. Such identities are able to manage secrets in various **Clients** throughout the entire infrastructure. To do that, identities have to verify themselves through one of the available **Authentication Methods**.
|
||||
|
||||
As a result, the 3 main concepts that are important to understand are:
|
||||
- **[Identities](/documentation/platform/identities/overview)**: users or machines with a set permissions assigned to them.
|
||||
- **[Clients](/integrations/platforms/kubernetes)**: Infisical-developed tools for managing secrets in various infrastructure components (e.g., [Kubernetes Operator](/integrations/platforms/kubernetes), [Infisical Agent](/integrations/platforms/infisical-agent), [CLI](/cli/usage), [SDKs](/sdks/overview), [API](/api-reference/overview/introduction), [Web Dashboard](/documentation/platform/organization)).
|
||||
- **[Authentication Methods](/documentation/platform/identities/universal-auth)**: ways for Identities to authenticate inside different clients (e.g., SAML SSO for Web Dashboard, Universal Auth for Infisical Agent, etc.).
|
||||
|
||||
## How to get started with Infisical?
|
||||
|
||||
Depending on your use case, it might be helpful to look into some of the resources and guides provided below.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card href="../../cli/overview" title="Command Line Interface (CLI)" icon="square-terminal" color="#000000">
|
||||
Inject secrets into any application process/environment.
|
||||
</Card>
|
||||
<Card
|
||||
title="SDKs"
|
||||
href="/documentation/getting-started/sdks"
|
||||
icon="boxes-stacked"
|
||||
color="#000000"
|
||||
>
|
||||
Fetch secrets with any programming language on demand.
|
||||
</Card>
|
||||
<Card href="../../integrations/platforms/docker-intro" title="Docker" icon="docker" color="#000000">
|
||||
Inject secrets into Docker containers.
|
||||
</Card>
|
||||
<Card
|
||||
href="../../integrations/platforms/kubernetes"
|
||||
title="Kubernetes"
|
||||
icon="server"
|
||||
color="#000000"
|
||||
>
|
||||
Fetch and save secrets as native Kubernetes secrets.
|
||||
</Card>
|
||||
<Card
|
||||
href="/documentation/getting-started/api"
|
||||
title="REST API"
|
||||
icon="cloud"
|
||||
color="#000000"
|
||||
>
|
||||
Fetch secrets via HTTP request.
|
||||
</Card>
|
||||
<Card
|
||||
href="/integrations/overview"
|
||||
title="Native Integrations"
|
||||
icon="clouds"
|
||||
color="#000000"
|
||||
>
|
||||
Explore integrations for GitHub, Vercel, AWS, and more.
|
||||
</Card>
|
||||
</CardGroup>
|
BIN
company/favicon.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
5
company/logo/dark.svg
Normal file
After Width: | Height: | Size: 6.8 KiB |
5
company/logo/light.svg
Normal file
After Width: | Height: | Size: 6.8 KiB |
80
company/mint.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "Infisical",
|
||||
"openapi": "https://app.infisical.com/api/docs/json",
|
||||
"logo": {
|
||||
"dark": "/logo/dark.svg",
|
||||
"light": "/logo/light.svg",
|
||||
"href": "https://infisical.com"
|
||||
},
|
||||
"favicon": "/favicon.png",
|
||||
"colors": {
|
||||
"primary": "#26272b",
|
||||
"light": "#97b31d",
|
||||
"dark": "#A1B659",
|
||||
"ultraLight": "#E7F256",
|
||||
"ultraDark": "#8D9F4C",
|
||||
"background": {
|
||||
"light": "#ffffff",
|
||||
"dark": "#0D1117"
|
||||
},
|
||||
"anchors": {
|
||||
"from": "#000000",
|
||||
"to": "#707174"
|
||||
}
|
||||
},
|
||||
"modeToggle": {
|
||||
"default": "light",
|
||||
"isHidden": true
|
||||
},
|
||||
"feedback": {
|
||||
"suggestEdit": true,
|
||||
"raiseIssue": true,
|
||||
"thumbsRating": true
|
||||
},
|
||||
"api": {
|
||||
"baseUrl": ["https://app.infisical.com", "http://localhost:8080"]
|
||||
},
|
||||
"topbarLinks": [
|
||||
{
|
||||
"name": "Log In",
|
||||
"url": "https://app.infisical.com/login"
|
||||
}
|
||||
],
|
||||
"topbarCtaButton": {
|
||||
"name": "Start for Free",
|
||||
"url": "https://app.infisical.com/signup"
|
||||
},
|
||||
"tabs": [
|
||||
{
|
||||
"name": "Integrations",
|
||||
"url": "integrations"
|
||||
},
|
||||
{
|
||||
"name": "CLI",
|
||||
"url": "cli"
|
||||
},
|
||||
{
|
||||
"name": "API Reference",
|
||||
"url": "api-reference"
|
||||
},
|
||||
{
|
||||
"name": "SDKs",
|
||||
"url": "sdks"
|
||||
},
|
||||
{
|
||||
"name": "Changelog",
|
||||
"url": "changelog"
|
||||
}
|
||||
],
|
||||
"navigation": [
|
||||
{
|
||||
"group": "Getting Started",
|
||||
"pages": [
|
||||
"documentation/getting-started/introduction"
|
||||
]
|
||||
}
|
||||
],
|
||||
"integrations": {
|
||||
"intercom": "hsg644ru"
|
||||
}
|
||||
}
|
142
company/style.css
Normal file
@@ -0,0 +1,142 @@
|
||||
#navbar .max-w-8xl {
|
||||
max-width: 100%;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
background-color: #fcfcfc;
|
||||
}
|
||||
|
||||
.max-w-8xl {
|
||||
/* background-color: #f5f5f5; */
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
left: 0;
|
||||
padding-left: 48px;
|
||||
padding-right: 30px;
|
||||
border-right: 1px;
|
||||
border-color: #cdd64b;
|
||||
background-color: #fcfcfc;
|
||||
border-right: 1px solid #ebebeb;
|
||||
}
|
||||
|
||||
#sidebar .relative .sticky {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#sidebar li > div.mt-2 {
|
||||
border-radius: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#sidebar li > a.mt-2 {
|
||||
border-radius: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#sidebar li > a.leading-6 {
|
||||
border-radius: 0;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* #sidebar ul > div.mt-12 {
|
||||
padding-top: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#sidebar ul > div.mt-12 h5 {
|
||||
position: absolute;
|
||||
left: -12px;
|
||||
top: -0px;
|
||||
} */
|
||||
|
||||
#header {
|
||||
border-left: 1px solid #26272b;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#content-area .mt-8 .block{
|
||||
border-radius: 0;
|
||||
border-width: 1px;
|
||||
border-color: #ebebeb;
|
||||
}
|
||||
|
||||
#content-area .mt-8 .rounded-xl{
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area .mt-8 .rounded-lg{
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area .mt-6 .rounded-xl{
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area .mt-6 .rounded-lg{
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area .mt-6 .rounded-md{
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area .mt-8 .rounded-md{
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area div.my-4{
|
||||
border-radius: 0;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
#content-area div.flex-1 {
|
||||
/* text-transform: uppercase; */
|
||||
opacity: 0.8;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
#content-area button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area a {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#content-area .not-prose {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* .eyebrow {
|
||||
text-transform: uppercase;
|
||||
font-weight: 400;
|
||||
color: red;
|
||||
} */
|
||||
|
||||
#content-container {
|
||||
/* background-color: #f5f5f5; */
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#topbar-cta-button .group .absolute {
|
||||
background-color: black;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
/* #topbar-cta-button .group .absolute:hover {
|
||||
background-color: white;
|
||||
border-radius: 0px;
|
||||
} */
|
||||
|
||||
#topbar-cta-button .group .flex {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.flex-1 .flex .items-center {
|
||||
/* background-color: #f5f5f5; */
|
||||
}
|
59
docker-swarm/.env-example
Normal file
@@ -0,0 +1,59 @@
|
||||
# Keys
|
||||
# Required key for platform encryption/decryption ops
|
||||
# THIS IS A SAMPLE ENCRYPTION KEY AND SHOULD NEVER BE USED FOR PRODUCTION
|
||||
ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218
|
||||
|
||||
# JWT
|
||||
# Required secrets to sign JWT tokens
|
||||
# THIS IS A SAMPLE AUTH_SECRET KEY AND SHOULD NEVER BE USED FOR PRODUCTION
|
||||
AUTH_SECRET=5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE=
|
||||
|
||||
DB_CONNECTION_URI=postgres://infisical:infisical@haproxy:5433/infisical?sslmode=no-verify
|
||||
# Redis
|
||||
REDIS_URL=redis://:123456@haproxy:6379
|
||||
|
||||
|
||||
# Website URL
|
||||
# Required
|
||||
SITE_URL=http://localhost:8080
|
||||
|
||||
# Mail/SMTP
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=
|
||||
SMTP_NAME=
|
||||
SMTP_USERNAME=
|
||||
SMTP_PASSWORD=
|
||||
|
||||
# Integration
|
||||
# Optional only if integration is used
|
||||
CLIENT_ID_HEROKU=
|
||||
CLIENT_ID_VERCEL=
|
||||
CLIENT_ID_NETLIFY=
|
||||
CLIENT_ID_GITHUB=
|
||||
CLIENT_ID_GITLAB=
|
||||
CLIENT_ID_BITBUCKET=
|
||||
CLIENT_SECRET_HEROKU=
|
||||
CLIENT_SECRET_VERCEL=
|
||||
CLIENT_SECRET_NETLIFY=
|
||||
CLIENT_SECRET_GITHUB=
|
||||
CLIENT_SECRET_GITLAB=
|
||||
CLIENT_SECRET_BITBUCKET=
|
||||
CLIENT_SLUG_VERCEL=
|
||||
|
||||
# Sentry (optional) for monitoring errors
|
||||
SENTRY_DSN=
|
||||
|
||||
# Infisical Cloud-specific configs
|
||||
# Ignore - Not applicable for self-hosted version
|
||||
POSTHOG_HOST=
|
||||
POSTHOG_PROJECT_API_KEY=
|
||||
|
||||
# SSO-specific variables
|
||||
CLIENT_ID_GOOGLE_LOGIN=
|
||||
CLIENT_SECRET_GOOGLE_LOGIN=
|
||||
|
||||
CLIENT_ID_GITHUB_LOGIN=
|
||||
CLIENT_SECRET_GITHUB_LOGIN=
|
||||
|
||||
CLIENT_ID_GITLAB_LOGIN=
|
||||
CLIENT_SECRET_GITLAB_LOGIN=
|
78
docker-swarm/haproxy.cfg
Normal file
@@ -0,0 +1,78 @@
|
||||
global
|
||||
maxconn 10000
|
||||
log stdout format raw local0
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode tcp
|
||||
retries 3
|
||||
timeout client 30m
|
||||
timeout connect 10s
|
||||
timeout server 30m
|
||||
timeout check 5s
|
||||
|
||||
listen stats
|
||||
mode http
|
||||
bind *:7000
|
||||
stats enable
|
||||
stats uri /
|
||||
|
||||
resolvers hostdns
|
||||
nameserver dns 127.0.0.11:53
|
||||
resolve_retries 3
|
||||
timeout resolve 1s
|
||||
timeout retry 1s
|
||||
hold valid 5s
|
||||
|
||||
frontend postgres_master
|
||||
bind *:5433
|
||||
default_backend postgres_master_backend
|
||||
|
||||
frontend postgres_replicas
|
||||
bind *:5434
|
||||
default_backend postgres_replica_backend
|
||||
|
||||
|
||||
backend postgres_master_backend
|
||||
option httpchk GET /master
|
||||
http-check expect status 200
|
||||
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
|
||||
server postgres-1 postgres-1:5432 check port 8008 resolvers hostdns
|
||||
server postgres-2 postgres-2:5432 check port 8008 resolvers hostdns
|
||||
server postgres-3 postgres-3:5432 check port 8008 resolvers hostdns
|
||||
|
||||
backend postgres_replica_backend
|
||||
option httpchk GET /replica
|
||||
http-check expect status 200
|
||||
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
|
||||
server postgres-1 postgres-1:5432 check port 8008 resolvers hostdns
|
||||
server postgres-2 postgres-2:5432 check port 8008 resolvers hostdns
|
||||
server postgres-3 postgres-3:5432 check port 8008 resolvers hostdns
|
||||
|
||||
|
||||
frontend redis_master_frontend
|
||||
bind *:6379
|
||||
default_backend redis_master_backend
|
||||
|
||||
backend redis_master_backend
|
||||
option tcp-check
|
||||
tcp-check send AUTH\ 123456\r\n
|
||||
tcp-check expect string +OK
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send info\ replication\r\n
|
||||
tcp-check expect string role:master
|
||||
tcp-check send QUIT\r\n
|
||||
tcp-check expect string +OK
|
||||
server redis_master redis_replica0:6379 check inter 1s
|
||||
server redis_replica1 redis_replica1:6379 check inter 1s
|
||||
server redis_replica2 redis_replica2:6379 check inter 1s
|
||||
|
||||
frontend infisical_frontend
|
||||
bind *:8080
|
||||
default_backend infisical_backend
|
||||
|
||||
backend infisical_backend
|
||||
option httpchk GET /api/status
|
||||
http-check expect status 200
|
||||
server infisical infisical:8080 check inter 1s
|
261
docker-swarm/stack.yaml
Normal file
@@ -0,0 +1,261 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
haproxy:
|
||||
image: haproxy:latest
|
||||
ports:
|
||||
- '7001:7000'
|
||||
- '5002:5433' # Postgres master
|
||||
- '5003:5434' # Postgres read
|
||||
- '6379:6379'
|
||||
- '8080:8080'
|
||||
networks:
|
||||
- infisical
|
||||
configs:
|
||||
- source: haproxy-config
|
||||
target: /usr/local/etc/haproxy/haproxy.cfg
|
||||
deploy:
|
||||
mode: global
|
||||
|
||||
infisical:
|
||||
container_name: infisical-backend
|
||||
image: infisical/infisical:v0.60.1-postgres
|
||||
env_file: .env
|
||||
networks:
|
||||
- infisical
|
||||
secrets:
|
||||
- env_file
|
||||
deploy:
|
||||
replicas: 5
|
||||
|
||||
etcd1:
|
||||
image: ghcr.io/zalando/spilo-16:3.2-p2
|
||||
networks:
|
||||
- infisical
|
||||
environment:
|
||||
ETCD_UNSUPPORTED_ARCH: arm64
|
||||
container_name: demo-etcd1
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node1
|
||||
hostname: etcd1
|
||||
command: |
|
||||
etcd --name etcd1
|
||||
--listen-client-urls http://0.0.0.0:2379
|
||||
--listen-peer-urls=http://0.0.0.0:2380
|
||||
--advertise-client-urls http://etcd1:2379
|
||||
--initial-cluster=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
|
||||
--initial-advertise-peer-urls=http://etcd1:2380
|
||||
--initial-cluster-state=new
|
||||
|
||||
etcd2:
|
||||
image: ghcr.io/zalando/spilo-16:3.2-p2
|
||||
networks:
|
||||
- infisical
|
||||
environment:
|
||||
ETCD_UNSUPPORTED_ARCH: arm64
|
||||
container_name: demo-etcd2
|
||||
hostname: etcd2
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node2
|
||||
command: |
|
||||
etcd --name etcd2
|
||||
--listen-client-urls http://0.0.0.0:2379
|
||||
--listen-peer-urls=http://0.0.0.0:2380
|
||||
--advertise-client-urls http://etcd2:2379
|
||||
--initial-cluster=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
|
||||
--initial-advertise-peer-urls=http://etcd2:2380
|
||||
--initial-cluster-state=new
|
||||
|
||||
etcd3:
|
||||
image: ghcr.io/zalando/spilo-16:3.2-p2
|
||||
networks:
|
||||
- infisical
|
||||
environment:
|
||||
ETCD_UNSUPPORTED_ARCH: arm64
|
||||
container_name: demo-etcd3
|
||||
hostname: etcd3
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node3
|
||||
command: |
|
||||
etcd --name etcd3
|
||||
--listen-client-urls http://0.0.0.0:2379
|
||||
--listen-peer-urls=http://0.0.0.0:2380
|
||||
--advertise-client-urls http://etcd3:2379
|
||||
--initial-cluster=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
|
||||
--initial-advertise-peer-urls=http://etcd3:2380
|
||||
--initial-cluster-state=new
|
||||
|
||||
spolo1:
|
||||
image: ghcr.io/zalando/spilo-16:3.2-p2
|
||||
container_name: postgres-1
|
||||
networks:
|
||||
- infisical
|
||||
hostname: postgres-1
|
||||
environment:
|
||||
ETCD_HOSTS: etcd1:2379,etcd2:2379,etcd3:2379
|
||||
PGPASSWORD_SUPERUSER: "postgres"
|
||||
PGUSER_SUPERUSER: "postgres"
|
||||
SCOPE: infisical
|
||||
volumes:
|
||||
- postgres_data1:/home/postgres/pgdata
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node1
|
||||
|
||||
spolo2:
|
||||
image: ghcr.io/zalando/spilo-16:3.2-p2
|
||||
container_name: postgres-2
|
||||
networks:
|
||||
- infisical
|
||||
hostname: postgres-2
|
||||
environment:
|
||||
ETCD_HOSTS: etcd1:2379,etcd2:2379,etcd3:2379
|
||||
PGPASSWORD_SUPERUSER: "postgres"
|
||||
PGUSER_SUPERUSER: "postgres"
|
||||
SCOPE: infisical
|
||||
volumes:
|
||||
- postgres_data2:/home/postgres/pgdata
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node2
|
||||
|
||||
spolo3:
|
||||
image: ghcr.io/zalando/spilo-16:3.2-p2
|
||||
container_name: postgres-3
|
||||
networks:
|
||||
- infisical
|
||||
hostname: postgres-3
|
||||
environment:
|
||||
ETCD_HOSTS: etcd1:2379,etcd2:2379,etcd3:2379
|
||||
PGPASSWORD_SUPERUSER: "postgres"
|
||||
PGUSER_SUPERUSER: "postgres"
|
||||
SCOPE: infisical
|
||||
volumes:
|
||||
- postgres_data3:/home/postgres/pgdata
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node3
|
||||
|
||||
|
||||
redis_replica0:
|
||||
image: bitnami/redis:6.2.10
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=master
|
||||
- REDIS_PASSWORD=123456
|
||||
networks:
|
||||
- infisical
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node1
|
||||
|
||||
redis_replica1:
|
||||
image: bitnami/redis:6.2.10
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=slave
|
||||
- REDIS_MASTER_HOST=redis_replica0
|
||||
- REDIS_MASTER_PORT_NUMBER=6379
|
||||
- REDIS_MASTER_PASSWORD=123456
|
||||
- REDIS_PASSWORD=123456
|
||||
networks:
|
||||
- infisical
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node2
|
||||
|
||||
redis_replica2:
|
||||
image: bitnami/redis:6.2.10
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=slave
|
||||
- REDIS_MASTER_HOST=redis_replica0
|
||||
- REDIS_MASTER_PORT_NUMBER=6379
|
||||
- REDIS_MASTER_PASSWORD=123456
|
||||
- REDIS_PASSWORD=123456
|
||||
networks:
|
||||
- infisical
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node3
|
||||
|
||||
redis_sentinel1:
|
||||
image: bitnami/redis-sentinel:6.2.10
|
||||
environment:
|
||||
- REDIS_SENTINEL_QUORUM=2
|
||||
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=5000
|
||||
- REDIS_SENTINEL_FAILOVER_TIMEOUT=60000
|
||||
- REDIS_SENTINEL_PORT_NUMBER=26379
|
||||
- REDIS_MASTER_HOST=redis_replica1
|
||||
- REDIS_MASTER_PORT_NUMBER=6379
|
||||
- REDIS_MASTER_PASSWORD=123456
|
||||
networks:
|
||||
- infisical
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node1
|
||||
|
||||
redis_sentinel2:
|
||||
image: bitnami/redis-sentinel:6.2.10
|
||||
environment:
|
||||
- REDIS_SENTINEL_QUORUM=2
|
||||
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=5000
|
||||
- REDIS_SENTINEL_FAILOVER_TIMEOUT=60000
|
||||
- REDIS_SENTINEL_PORT_NUMBER=26379
|
||||
- REDIS_MASTER_HOST=redis_replica1
|
||||
- REDIS_MASTER_PORT_NUMBER=6379
|
||||
- REDIS_MASTER_PASSWORD=123456
|
||||
networks:
|
||||
- infisical
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node2
|
||||
|
||||
redis_sentinel3:
|
||||
image: bitnami/redis-sentinel:6.2.10
|
||||
environment:
|
||||
- REDIS_SENTINEL_QUORUM=2
|
||||
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=5000
|
||||
- REDIS_SENTINEL_FAILOVER_TIMEOUT=60000
|
||||
- REDIS_SENTINEL_PORT_NUMBER=26379
|
||||
- REDIS_MASTER_HOST=redis_replica1
|
||||
- REDIS_MASTER_PORT_NUMBER=6379
|
||||
- REDIS_MASTER_PASSWORD=123456
|
||||
networks:
|
||||
- infisical
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.name == node3
|
||||
|
||||
networks:
|
||||
infisical:
|
||||
|
||||
|
||||
volumes:
|
||||
postgres_data1:
|
||||
postgres_data2:
|
||||
postgres_data3:
|
||||
postgres_data4:
|
||||
redis0:
|
||||
redis1:
|
||||
redis2:
|
||||
|
||||
configs:
|
||||
haproxy-config:
|
||||
file: ./haproxy.cfg
|
||||
|
||||
secrets:
|
||||
env_file:
|
||||
file: .env
|
@@ -4,7 +4,7 @@ openapi: "GET /api/v2/service-token"
|
||||
---
|
||||
|
||||
<Warning>
|
||||
This endpoint will be deprecated in the near future with the removal of service tokens in Q1/Q2 2024.
|
||||
This endpoint is deprecated and will be removed in the future.
|
||||
|
||||
We recommend switching to using [identities](/documentation/platform/identities/overview) if your client supports it.
|
||||
We recommend switching to using [Machine Identities](/documentation/platform/identities/machine-identities).
|
||||
</Warning>
|
||||
|
@@ -39,13 +39,25 @@ Export environment variables from the platform into a file format.
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
<Accordion title="INFISICAL_TOKEN">
|
||||
Used to fetch secrets via a [service token](/documentation/platform/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
|
||||
Used to fetch secrets via a [machine identities](/documentation/platform/identities/machine-identities) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
|
||||
|
||||
```bash
|
||||
# Example
|
||||
export INFISICAL_TOKEN=st.63e03c4a97cb4a747186c71e.ed5b46a34c078a8f94e8228f4ab0ff97.4f7f38034811995997d72badf44b42ec
|
||||
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=<identity-client-id> --client-secret=<identity-client-secret> --silent --plain) # --plain flag will output only the token, so it can be fed to an environment variable. --silent will disable any update messages.
|
||||
```
|
||||
|
||||
<Info>
|
||||
Alternatively, you may use service tokens.
|
||||
|
||||
Please note, however, that service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities). They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
```bash
|
||||
# Example
|
||||
export INFISICAL_TOKEN=<service-token>
|
||||
```
|
||||
|
||||
</Info>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="INFISICAL_DISABLE_UPDATE_CHECK">
|
||||
@@ -57,9 +69,11 @@ Export environment variables from the platform into a file format.
|
||||
# Example
|
||||
export INFISICAL_DISABLE_UPDATE_CHECK=true
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
### flags
|
||||
|
||||
<Accordion title="--template">
|
||||
The `--template` flag specifies the path to the template file used for rendering secrets. When using templates, you can omit the other format flags.
|
||||
|
||||
@@ -79,6 +93,7 @@ Export environment variables from the platform into a file format.
|
||||
# Example
|
||||
infisical export --template="/path/to/template/file"
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="--env">
|
||||
Used to set the environment that secrets are pulled from.
|
||||
@@ -91,6 +106,7 @@ Export environment variables from the platform into a file format.
|
||||
Note: this flag only accepts environment slug names not the fully qualified name. To view the slug name of an environment, visit the project settings page.
|
||||
|
||||
default value: `dev`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--projectId">
|
||||
@@ -102,24 +118,28 @@ Export environment variables from the platform into a file format.
|
||||
|
||||
infisical export --projectId=XXXXXXXXXXXXXX
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--expand">
|
||||
Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`)
|
||||
|
||||
Default value: `true`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--format">
|
||||
Format of the output file. Accepted values: `dotenv`, `dotenv-export`, `csv`, `json` and `yaml`
|
||||
|
||||
Default value: `dotenv`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--secret-overriding">
|
||||
Prioritizes personal secrets with the same name over shared secrets
|
||||
|
||||
Default value: `true`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--path">
|
||||
@@ -129,6 +149,7 @@ Export environment variables from the platform into a file format.
|
||||
# Example
|
||||
infisical export --path="/path/to/folder" --env=dev
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--tags">
|
||||
@@ -142,6 +163,7 @@ Export environment variables from the platform into a file format.
|
||||
Note: you must reference the tag by its slug name not its fully qualified name. Go to project settings to view all tag slugs.
|
||||
|
||||
By default, all secrets are fetched
|
||||
|
||||
</Accordion>
|
||||
|
||||
</Accordion>
|
||||
|
@@ -11,6 +11,7 @@ description: "The command that injects your secrets into local environment"
|
||||
# Example
|
||||
infisical run [options] -- npm run dev
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Chained commands">
|
||||
@@ -20,6 +21,7 @@ description: "The command that injects your secrets into local environment"
|
||||
# Example
|
||||
infisical run [options] --command "npm run bootstrap && npm run dev start; other-bash-command"
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
@@ -27,7 +29,6 @@ description: "The command that injects your secrets into local environment"
|
||||
|
||||
Inject secrets from Infisical into your application process.
|
||||
|
||||
|
||||
## Subcommands & flags
|
||||
|
||||
<Accordion title="infisical run" defaultOpen="true">
|
||||
@@ -41,13 +42,25 @@ Inject secrets from Infisical into your application process.
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
<Accordion title="INFISICAL_TOKEN">
|
||||
Used to fetch secrets via a [service token](/documentation/platform/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
|
||||
Used to fetch secrets via a [machine identity](/documentation/platform/identities/machine-identities) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
|
||||
|
||||
```bash
|
||||
# Example
|
||||
export INFISICAL_TOKEN=st.63e03c4a97cb4a747186c71e.ed5b46a34c078a8f94e8228f4ab0ff97.4f7f38034811995997d72badf44b42ec
|
||||
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=<identity-client-id> --client-secret=<identity-client-secret> --silent --plain) # --plain flag will output only the token, so it can be fed to an environment variable. --silent will disable any update messages.
|
||||
```
|
||||
|
||||
<Info>
|
||||
Alternatively, you may use service tokens.
|
||||
|
||||
Please note, however, that service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities). They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
```bash
|
||||
# Example
|
||||
export INFISICAL_TOKEN=<service-token>
|
||||
```
|
||||
|
||||
</Info>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="INFISICAL_DISABLE_UPDATE_CHECK">
|
||||
@@ -59,6 +72,7 @@ Inject secrets from Infisical into your application process.
|
||||
# Example
|
||||
export INFISICAL_DISABLE_UPDATE_CHECK=true
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
### Flags
|
||||
@@ -70,6 +84,7 @@ Inject secrets from Infisical into your application process.
|
||||
# Example
|
||||
infisical run --project-config-dir=/some-dir -- printenv
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--command">
|
||||
@@ -79,35 +94,51 @@ Inject secrets from Infisical into your application process.
|
||||
# Example
|
||||
infisical run --command="npm run build && npm run dev; more-commands..."
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--token">
|
||||
If you are using a [service token](/documentation/platform/token) to authenticate, you can pass the token as a flag
|
||||
<Accordion title="--projectId">
|
||||
The project ID to fetch secrets from. This is required when using a machine identity to authenticate.
|
||||
|
||||
```bash
|
||||
# Example
|
||||
infisical run --token="st.63e03c4a97cb4a747186c71e.ed5b46a34c078a8f94e8228f4ab0ff97.4f7f38034811995997d72badf44b42ec" -- npm run start
|
||||
infisical run --projectId=<project-id> -- npm run dev
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--token">
|
||||
If you are using a [machine identity](/documentation/platform/identities/machine-identities) to authenticate, you can pass the token as a flag
|
||||
|
||||
```bash
|
||||
# Example
|
||||
infisical run --token="<universal-auth-access-token>" --projectId=<project-id> -- npm run start
|
||||
```
|
||||
|
||||
You may also expose the token to the CLI by setting the environment variable `INFISICAL_TOKEN` before executing the run command. This will have the same effect as setting the token with `--token` flag
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--expand">
|
||||
Turn on or off the shell parameter expansion in your secrets. If you have used shell parameters in your secret(s), activating this feature will populate them before injecting them into your application process.
|
||||
|
||||
Default value: `true`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--env">
|
||||
This is used to specify the environment from which secrets should be retrieved. The accepted values are the environment slugs defined for your project, such as `dev`, `staging`, `test`, and `prod`.
|
||||
{" "}
|
||||
|
||||
Default value: `dev`
|
||||
<Accordion title="--env">
|
||||
This is used to specify the environment from which secrets should be
|
||||
retrieved. The accepted values are the environment slugs defined for your
|
||||
project, such as `dev`, `staging`, `test`, and `prod`. Default value: `dev`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--secret-overriding">
|
||||
Prioritizes personal secrets with the same name over shared secrets
|
||||
|
||||
Default value: `true`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--tags">
|
||||
@@ -121,6 +152,7 @@ Inject secrets from Infisical into your application process.
|
||||
Note: you must reference the tag by its slug name not its fully qualified name. Go to project settings to view all tag slugs.
|
||||
|
||||
By default, all secrets are fetched
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--path">
|
||||
|
@@ -23,13 +23,23 @@ $ infisical secrets
|
||||
### Environment variables
|
||||
|
||||
<Accordion title="INFISICAL_TOKEN">
|
||||
Used to fetch secrets via a [service token](/documentation/platform/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
|
||||
Used to fetch secrets via a [machine identity](/documentation/platform/identities/machine-identities) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
|
||||
|
||||
```bash
|
||||
# Example
|
||||
export INFISICAL_TOKEN=st.63e03c4a97cb4a747186c71e.ed5b46a34c078a8f94e8228f4ab0ff97.4f7f38034811995997d72badf44b42ec
|
||||
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=<identity-client-id> --client-secret=<identity-client-secret> --silent --plain) # --plain flag will output only the token, so it can be fed to an environment variable. --silent will disable any update messages.
|
||||
```
|
||||
|
||||
<Info>
|
||||
Alternatively, you may use service tokens.
|
||||
|
||||
Please note, however, that service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities). They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
```bash
|
||||
# Example
|
||||
export INFISICAL_TOKEN=<service-token>
|
||||
```
|
||||
</Info>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="INFISICAL_DISABLE_UPDATE_CHECK">
|
||||
@@ -53,6 +63,16 @@ $ infisical secrets
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--projectId">
|
||||
The project ID to fetch secrets from. This is required when using a machine identity to authenticate.
|
||||
|
||||
```bash
|
||||
# Example
|
||||
infisical secrets --projectId=<project-id>
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--env">
|
||||
Used to select the environment name on which actions should be taken on
|
||||
|
||||
@@ -186,7 +206,7 @@ $ infisical secrets folders
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--token">
|
||||
Fetch folders using the Infisical service token
|
||||
Fetch folders using a [machine identity](/documentation/platform/identities/machine-identities) access token.
|
||||
|
||||
Default value: ``
|
||||
</Accordion>
|
||||
|
@@ -3,11 +3,19 @@ title: "infisical service-token"
|
||||
description: "Manage Infisical service tokens"
|
||||
---
|
||||
|
||||
<Warning>
|
||||
This command is deprecated and will be removed in the near future. Please
|
||||
switch to using [Machine
|
||||
Identities](/documentation/platform/identities/machine-identities) for
|
||||
authenticating with Infisical.
|
||||
</Warning>
|
||||
|
||||
```bash
|
||||
infisical service-token create --scope=dev:/global --scope=dev:/backend --access-level=read --access-level=write
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
The Infisical `service-token` command allows you to manage service tokens for a given Infisical project.
|
||||
With this command, you can create, view, and delete service tokens.
|
||||
|
||||
@@ -19,6 +27,7 @@ With this command, you can create, view, and delete service tokens.
|
||||
```
|
||||
|
||||
### Flags
|
||||
|
||||
<Accordion title="--scope">
|
||||
```bash
|
||||
infisical service-token create --scope=dev:/global --scope=dev:/backend/** --access-level=read
|
||||
@@ -34,6 +43,7 @@ With this command, you can create, view, and delete service tokens.
|
||||
<Info>
|
||||
The `path` can be a Glob pattern
|
||||
</Info>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="--projectId">
|
||||
@@ -43,6 +53,7 @@ With this command, you can create, view, and delete service tokens.
|
||||
|
||||
The project ID you'd like to create the service token for.
|
||||
By default, the CLI will attempt to use the linked Infisical project in `.infisical.json` generated by `infisical init` command.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="--name">
|
||||
```bash
|
||||
@@ -52,6 +63,7 @@ With this command, you can create, view, and delete service tokens.
|
||||
Service token name
|
||||
|
||||
Default: `Service token generated via CLI`
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="--expiry-seconds">
|
||||
```bash
|
||||
@@ -61,6 +73,7 @@ With this command, you can create, view, and delete service tokens.
|
||||
Set the service token's expiration time in seconds from now. To never expire set to zero.
|
||||
|
||||
Default: `1 day`
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="--access-level">
|
||||
```bash
|
||||
@@ -68,6 +81,7 @@ With this command, you can create, view, and delete service tokens.
|
||||
```
|
||||
|
||||
The type of access the service token should have. Can be `read` and or `write`
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="--token-only">
|
||||
```bash
|
||||
@@ -77,5 +91,6 @@ With this command, you can create, view, and delete service tokens.
|
||||
When true, only the service token will be printed
|
||||
|
||||
Default: `false`
|
||||
|
||||
</Accordion>
|
||||
</Accordion>
|
||||
|
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: "Infisical Token"
|
||||
description: "How to use Infisical service token within the CLI."
|
||||
---
|
||||
|
||||
Prerequisite: [Infisical Token and How to Generate One](/documentation/platform/token).
|
||||
|
||||
It's possible to use the CLI to sync environment variables without manually entering login credentials by using a service token in the prerequisite link above.
|
||||
|
||||
## Feeding Infisical Token to the CLI
|
||||
|
||||
The CLI looks out for an environment variable called the `INFISICAL_TOKEN` which you can set depending on where you run the CLI. If `INFISICAL_TOKEN` is detected by the CLI, it will authenticate and retrieve the environment variables which the token is authorized for.
|
||||
|
||||
A common use-case is to use the Infisical Token to fetch environment variables with Docker. More specifically, a token can be passed to a container as an environment variable for the CLI to authenticate and pull its corresponding secrets. Check out the integration guides for that:
|
||||
|
||||
- [Docker](../../integrations/platforms/docker)
|
||||
- [Docker Compose](../../integrations/platforms/docker-compose)
|
||||
|
||||
<Info>
|
||||
Once the token is expired, the CLI using it will no longer be able to make
|
||||
requests with it.
|
||||
</Info>
|
@@ -1,24 +1,28 @@
|
||||
---
|
||||
title: "Quick usage"
|
||||
title: "Quickstart"
|
||||
description: "Manage secrets with Infisical CLI"
|
||||
---
|
||||
|
||||
The CLI is designed for a variety of applications, ranging from local secret management to CI/CD and production scenarios.
|
||||
The distinguishing factor, however, is the authentication method used.
|
||||
The CLI is designed for a variety of secret management applications ranging from local development to CI/CD and production scenarios.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Local development only">
|
||||
To use the Infisical CLI in your local development environment, simply run the command below and follow the interactive guide.
|
||||
<Tab title="Local development">
|
||||
In the following steps, we explore how to use the Infisical CLI to fetch back environment variables from Infisical
|
||||
and inject them into your local development process.
|
||||
|
||||
<Steps>
|
||||
<Step title="Log in with the CLI">
|
||||
Start by running the `infisical login` command to authenticate with Infisical.
|
||||
|
||||
```bash
|
||||
infisical login
|
||||
```
|
||||
|
||||
<Note>
|
||||
If you are in a containerized environment such as WSL 2 or Codespaces, run `infisical login -i` to avoid browser based login
|
||||
</Note>
|
||||
|
||||
## Initialize Infisical for your project
|
||||
</Step>
|
||||
<Step title="Initialize Infisical for your project">
|
||||
Next, navigate to your project and initialize Infisical.
|
||||
|
||||
```bash
|
||||
# navigate to your project
|
||||
@@ -28,40 +32,19 @@ The distinguishing factor, however, is the authentication method used.
|
||||
infisical init
|
||||
```
|
||||
|
||||
This will create `.infisical.json` file at the location the command was executed. This file contains your [local project settings](./project-config). It does not contain any sensitive data.
|
||||
The `infisical init` command creates a `.infisical.json` file, containing [local project settings](./project-config), at the location where the command is executed.
|
||||
|
||||
</Tab>
|
||||
<Note>
|
||||
The `.infisical.json` file does not contain any sensitive data, so you may commit it to your git repository.
|
||||
</Note>
|
||||
</Step>
|
||||
<Step title="Inject environment variables">
|
||||
Finally, pass environment variables from Infisical into your application.
|
||||
|
||||
<Tab title="Staging, production & all other use case">
|
||||
To use Infisical for non local development scenarios, please create a [service token](../documentation/platform/token). The service token will allow you to authenticate and interact with Infisical.
|
||||
Once you have created a service token with the required permissions, you'll need to feed the token to the CLI.
|
||||
|
||||
#### Pass as flag
|
||||
You may use the --token flag to set the token
|
||||
|
||||
```
|
||||
infisical export --token=<>
|
||||
infisical secrets --token=<>
|
||||
infisical run --token=<> -- npm run dev
|
||||
```
|
||||
|
||||
#### Pass via shell environment variable
|
||||
The CLI is configured to look for an environment variable named `INFISICAL_TOKEN`. If set, it'll attempt to use it for authentication.
|
||||
|
||||
```
|
||||
export INFISICAL_TOKEN=<>
|
||||
```
|
||||
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Inject environment variables
|
||||
<Tabs>
|
||||
<Tab title="Feed secrets to your application">
|
||||
```bash
|
||||
infisical run --env=dev --path=/apps/firefly -- [your application start command]
|
||||
infisical run --env=dev --path=/apps/firefly -- [your application start command] # e.g. npm run dev
|
||||
|
||||
# example with node (nodemon)
|
||||
infisical run --env=staging --path=/apps/spotify -- nodemon index.js
|
||||
@@ -72,6 +55,7 @@ The distinguishing factor, however, is the authentication method used.
|
||||
# example with spring boot - maven
|
||||
infisical run --env=dev --path=/apps/ -- ./mvnw spring-boot:run --quiet
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Feed secrets via custom aliases (advanced)">
|
||||
Custom aliases can utilize secrets from Infisical. Suppose there is a custom alias `yd` in `custom.sh` that runs `yarn dev` and needs the secrets provided by Infisical.
|
||||
@@ -92,50 +76,50 @@ The distinguishing factor, however, is the authentication method used.
|
||||
</Tabs>
|
||||
|
||||
View all available options for `run` command [here](./commands/run)
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Connect CLI to self hosted Infisical
|
||||
|
||||
<Accordion title="Optional: point CLI to self-hosted">
|
||||
The CLI is set to connect to Infisical Cloud by default, but if you're running your own instance of Infisical, you can direct the CLI to it using one of the methods provided below.
|
||||
|
||||
#### Method 1: Use the updated CLI
|
||||
Beginning with CLI version V0.4.0, it is now possible to choose between logging in through the Infisical cloud or your own self-hosted instance. Simply execute the `infisical login` command and follow the on-screen instructions.
|
||||
|
||||
#### Method 2: Export environment variable
|
||||
You can point the CLI to the self hosted Infisical instance by exporting the environment variable `INFISICAL_API_URL` in your terminal.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Linux/MacOs">
|
||||
```bash
|
||||
# Set backend host
|
||||
export INFISICAL_API_URL="https://your-self-hosted-infisical.com/api"
|
||||
|
||||
# Remove backend host
|
||||
unset INFISICAL_API_URL
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Windows Powershell">
|
||||
|
||||
<Tab title="Staging, production & all other use cases">
|
||||
In the following steps, we explore how to use the Infisical CLI in a non-local development scenario
|
||||
to fetch back environment variables and export them to a file.
|
||||
<Steps>
|
||||
<Step title="Create a machine identity and obtain credentials for it">
|
||||
Follow the steps listed [here](/documentation/platform/identities/universal-auth) to create a machine identity and obtain a **client ID** and **client secret** for it.
|
||||
</Step>
|
||||
<Step title="Obtain a machine identity access token">
|
||||
Run the following command to authenticate with Infisical using the **client ID** and **client secret** credentials from step 1 and set the `INFISICAL_TOKEN` environment variable to the retrieved access token.
|
||||
|
||||
```bash
|
||||
# Set backend host
|
||||
setx INFISICAL_API_URL "https://your-self-hosted-infisical.com/api"
|
||||
|
||||
# Remove backend host
|
||||
setx INFISICAL_API_URL ""
|
||||
|
||||
# NOTE: Once set or removed, please restart powershell for the change to take effect
|
||||
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=<identity-client-id> --client-secret=<identity-client-secret> --silent --plain) # --plain flag will output only the token, so it can be fed to an environment variable. --silent will disable any update messages.
|
||||
```
|
||||
|
||||
The CLI is configured to look out for the `INFISICAL_TOKEN` environment variable, so going forward any command used will be authenticated.
|
||||
|
||||
Alternatively, assuming you have an access token on hand, you can also pass it directly to the CLI using the `--token` flag in conjunction with other CLI commands.
|
||||
|
||||
<Info>
|
||||
Keep in mind that the machine identity access token has a limited lifetime. It is recommended to use it only for the duration of the task at hand.
|
||||
You can [refresh the token](./commands/token) if needed.
|
||||
</Info>
|
||||
</Step>
|
||||
<Step title="Export environment variables back into a file">
|
||||
Finally, export the environment variables from Infisical to a file of choice.
|
||||
|
||||
```bash
|
||||
# export variables to a .env file (with export keyword)
|
||||
infisical export --format=dotenv-export > .env
|
||||
|
||||
# export variables to a YAML file
|
||||
infisical export --format=yaml > secrets.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
#### Method 3: Set manually on every command
|
||||
Another option to point the CLI to your self hosted Infisical instance is to set it via a flag on every command you run.
|
||||
|
||||
```bash
|
||||
# Example
|
||||
infisical <any-command> --domain="https://your-self-hosted-infisical.com/api"
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
## History
|
||||
|
||||
Your terminal keeps a history with the commands you run. When you create Infisical secrets directly from your terminal, they'll stay there for a while.
|
||||
@@ -143,7 +127,6 @@ Your terminal keeps a history with the commands you run. When you create Infisic
|
||||
For security and privacy concerns, we recommend you to configure your terminal to ignore those specific Infisical commands.
|
||||
|
||||
<Accordion title="Ignore commands">
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Unix/Linux">
|
||||
<Tip>
|
||||
@@ -168,5 +151,77 @@ For security and privacy concerns, we recommend you to configure your terminal t
|
||||
</Tip>
|
||||
|
||||
</Tab>
|
||||
|
||||
</Tabs>
|
||||
</Accordion>
|
||||
|
||||
## FAQ
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Can I connect the CLI to my self-hosted Infisical instance?">
|
||||
Yes. The CLI is set to connect to Infisical Cloud by default, but if you're running your own instance of Infisical, you can direct the CLI to it using one of the methods provided below.
|
||||
|
||||
#### Method 1: Use the updated CLI
|
||||
|
||||
Beginning with CLI version V0.4.0, it is now possible to choose between logging in through the Infisical cloud or your own self-hosted instance. Simply execute the `infisical login` command and follow the on-screen instructions.
|
||||
|
||||
#### Method 2: Export environment variable
|
||||
|
||||
You can point the CLI to the self hosted Infisical instance by exporting the environment variable `INFISICAL_API_URL` in your terminal.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Linux/MacOs">
|
||||
```bash
|
||||
# set backend host
|
||||
export INFISICAL_API_URL="https://your-self-hosted-infisical.com/api"
|
||||
|
||||
# remove backend host
|
||||
unset INFISICAL_API_URL
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Windows Powershell">
|
||||
```bash
|
||||
# set backend host
|
||||
setx INFISICAL_API_URL "https://your-self-hosted-infisical.com/api"
|
||||
|
||||
# remove backend host
|
||||
setx INFISICAL_API_URL ""
|
||||
|
||||
# NOTE: Once set or removed, please restart powershell for the change to take effect
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
</Tabs>
|
||||
|
||||
#### Method 3: Set manually on every command
|
||||
|
||||
Another option to point the CLI to your self hosted Infisical instance is to set it via a flag on every command you run.
|
||||
|
||||
```bash
|
||||
# Example
|
||||
infisical <any-command> --domain="https://your-self-hosted-infisical.com/api"
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Can I use the CLI with service tokens?">
|
||||
Yes. Please note, however, that service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities). They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
To use Infisical for non local development scenarios, please create a service token. The service token will allow you to authenticate and interact with Infisical. Once you have created a service token with the required permissions, you’ll need to feed the token to the CLI.
|
||||
|
||||
```bash
|
||||
infisical export --token=<service-token>
|
||||
infisical secrets --token=<service-token>
|
||||
infisical run --token=<service-token> -- npm run dev
|
||||
```
|
||||
|
||||
#### Pass via shell environment variable
|
||||
The CLI is configured to look for an environment variable named `INFISICAL_TOKEN`. If set, it’ll attempt to use it for authentication.
|
||||
|
||||
```bash
|
||||
export INFISICAL_TOKEN=<service-token>
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
@@ -1,87 +0,0 @@
|
||||
---
|
||||
title: "Kubernetes"
|
||||
---
|
||||
|
||||
The Infisical Secrets Operator fetches secrets from Infisical and saves them as Kubernetes secrets using the custom `InfisicalSecret` resource to define authentication and storage methods.
|
||||
The operator updates secrets continuously and can reload dependent deployments automatically on secret changes.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Connected to your cluster via kubectl
|
||||
- Have a project with secrets ready in [Infisical Cloud](https://app.infisical.com).
|
||||
- Create an [Infisical Token](/documentation/platform/token) scoped to an environment in your project in Infisical.
|
||||
|
||||
## Installation
|
||||
|
||||
Follow the instructions for either [Helm](https://helm.sh/) or [kubectl](https://github.com/kubernetes/kubectl) to install the Infisical Secrets Operator.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Helm">
|
||||
Install the Infisical Helm repository
|
||||
|
||||
```console
|
||||
helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/'
|
||||
|
||||
helm repo update
|
||||
```
|
||||
|
||||
Install the Helm chart
|
||||
```console
|
||||
helm install --generate-name infisical-helm-charts/secrets-operator
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Kubectl">
|
||||
The operator will be installed in `infisical-operator-system` namespace
|
||||
```
|
||||
kubectl apply -f https://raw.githubusercontent.com/Infisical/infisical/main/k8-operator/kubectl-install/install-secrets-operator.yaml
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
**Step 1: Create Kubernetes secret containing service token**
|
||||
|
||||
Once you have generated the service token, create a Kubernetes secret containing the service token you generated by running the command below.
|
||||
|
||||
``` bash
|
||||
kubectl create secret generic service-token --from-literal=infisicalToken=<your-service-token-here>
|
||||
```
|
||||
|
||||
**Step 2: Fill out the InfisicalSecrets CRD and apply it to your cluster**
|
||||
|
||||
```yaml infisical-secrets-config.yaml
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
metadata:
|
||||
# Name of of this InfisicalSecret resource
|
||||
name: infisicalsecret-sample
|
||||
spec:
|
||||
# The host that should be used to pull secrets from. If left empty, the value specified in Global configuration will be used
|
||||
hostAPI: https://app.infisical.com/api
|
||||
resyncInterval:
|
||||
authentication:
|
||||
serviceToken:
|
||||
serviceTokenSecretReference:
|
||||
secretName: service-token
|
||||
secretNamespace: option
|
||||
secretsScope:
|
||||
envSlug: dev
|
||||
secretsPath: "/"
|
||||
managedSecretReference:
|
||||
secretName: managed-secret # <-- the name of kubernetes secret that will be created
|
||||
secretNamespace: default # <-- where the kubernetes secret should be created
|
||||
```
|
||||
|
||||
```
|
||||
kubectl apply -f infisical-secrets-config.yaml
|
||||
```
|
||||
|
||||
You should now see a new kubernetes secret automatically created in the namespace you defined in the `managedSecretReference` property above.
|
||||
|
||||
See also:
|
||||
|
||||
- [Documentation for the Infisical Kubernetes Operator](../../integrations/platforms/kubernetes)
|
||||
|
82
docs/documentation/platform/audit-log-streams.mdx
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: "Audit Log Streams"
|
||||
description: "Learn how to stream Infisical Audit Logs to external logging providers."
|
||||
---
|
||||
|
||||
<Info>
|
||||
Audit log streams is a paid feature.
|
||||
|
||||
If you're using Infisical Cloud, then it is available under the **Enterprise Tier**. If you're self-hosting Infisical,
|
||||
then you should contact team@infisical.com to purchase an enterprise license to use it.
|
||||
</Info>
|
||||
|
||||
Infisical Audit Log Streaming enables you to transmit your organization's Audit Logs to external logging providers for monitoring and analysis.
|
||||
|
||||
The logs are formatted in JSON, requiring your logging provider to support JSON-based log parsing.
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
<Steps>
|
||||
<Step title="Navigate to Organization Settings in your sidebar." />
|
||||
<Step title="Select Audit Log Streams Tab.">
|
||||

|
||||
</Step>
|
||||
<Step title="Click on Create">
|
||||

|
||||
|
||||
Provide the following values
|
||||
<ParamField path="Endpoint URL" type="string" required>
|
||||
The HTTPS endpoint URL of the logging provider that collects the JSON stream.
|
||||
</ParamField>
|
||||
<ParamField path="Headers" type="string" >
|
||||
The HTTP headers for the logging provider for identification and authentication.
|
||||
</ParamField>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||

|
||||
Your Audit Logs are now ready to be streamed.
|
||||
|
||||
## Example Providers
|
||||
|
||||
### Better Stack
|
||||
|
||||
<Steps>
|
||||
<Step title="Select Connect Source">
|
||||

|
||||
</Step>
|
||||
<Step title="Provide a name and select platform"/>
|
||||
<Step title="Provide Audit Log Stream inputs">
|
||||

|
||||
|
||||
1. Copy the **endpoint** from Better Stack to the **Endpoint URL** field.
|
||||
3. Create a new header with key **Authorization** and set the value as **Bearer \<source token from betterstack\>**.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### Datadog
|
||||
|
||||
<Steps>
|
||||
<Step title="Navigate to API Keys section">
|
||||

|
||||
</Step>
|
||||
<Step title="Select New Key and provide a key name">
|
||||

|
||||

|
||||
</Step>
|
||||
<Step title="Find your Datadog region specific logging endpoint.">
|
||||

|
||||
|
||||
1. Navigate to the [Datadog Send Logs API documentation](https://docs.datadoghq.com/api/latest/logs/?code-lang=curl&site=us5#send-logs).
|
||||
2. Pick your Datadog account region.
|
||||
3. Obtain your Datadog logging endpoint URL.
|
||||
</Step>
|
||||
<Step title="Provide audit log stream inputs">
|
||||

|
||||
|
||||
1. Copy the **logging endpoint** from Datadog to the **Endpoint URL** field.
|
||||
2. Copy the **API Key** from previous step
|
||||
3. Create a new header with key **DD-API-KEY** and set the value as **API Key**.
|
||||
</Step>
|
||||
</Steps>
|
151
docs/documentation/platform/dynamic-secrets/aws-iam.mdx
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
title: "AWS IAM"
|
||||
description: "How to dynamically generate AWS IAM Users."
|
||||
---
|
||||
|
||||
The Infisical AWS IAM dynamic secret allows you to generate AWS IAM Users on demand based on configured AWS policy.
|
||||
|
||||
## Prerequisite
|
||||
|
||||
Infisical needs an initial AWS IAM user with the required permissions to create sub IAM users. This IAM user will be responsible for managing the lifecycle of new IAM users.
|
||||
|
||||
<Accordion title="Managing AWS IAM User minimum permission policy">
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"iam:AttachUserPolicy",
|
||||
"iam:CreateAccessKey",
|
||||
"iam:CreateUser",
|
||||
"iam:DeleteAccessKey",
|
||||
"iam:DeleteUser",
|
||||
"iam:DeleteUserPolicy",
|
||||
"iam:DetachUserPolicy",
|
||||
"iam:GetUser",
|
||||
"iam:ListAccessKeys",
|
||||
"iam:ListAttachedUserPolicies",
|
||||
"iam:ListGroupsForUser",
|
||||
"iam:ListUserPolicies",
|
||||
"iam:PutUserPolicy",
|
||||
"iam:AddUserToGroup",
|
||||
"iam:RemoveUserFromGroup"
|
||||
],
|
||||
"Resource": ["*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
To minimize managing user access you can attach a resource in format
|
||||
|
||||
> arn:aws:iam::\<account-id\>:user/\<aws-scope-path\>
|
||||
|
||||
Replace **\<account id\>** with your AWS account id and **\<aws-scope-path\>** with a path to minimize managing user access.
|
||||
|
||||
</Accordion>
|
||||
|
||||
## Set up Dynamic Secrets with AWS IAM
|
||||
|
||||
<Steps>
|
||||
<Step title="Secret Overview Dashboard">
|
||||
Navigate to the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret to.
|
||||
</Step>
|
||||
<Step title="Click on the 'Add Dynamic Secret' button">
|
||||

|
||||
</Step>
|
||||
<Step title="Select AWS IAM">
|
||||

|
||||
</Step>
|
||||
<Step title="Provide the inputs for dynamic secret parameters">
|
||||
<ParamField path="Secret Name" type="string" required>
|
||||
Name by which you want the secret to be referenced
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="Default TTL" type="string" required>
|
||||
Default time-to-live for a generated secret (it is possible to modify this value when a secret is generate)
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="Max TTL" type="string" required>
|
||||
Maximum time-to-live for a generated secret
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="AWS Access Key" type="string" required>
|
||||
The managing AWS IAM User Access Key
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="AWS Secret Key" type="string" required>
|
||||
The managing AWS IAM User Secret Key
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="AWS IAM Path" type="string">
|
||||
[IAM AWS Path](https://aws.amazon.com/blogs/security/optimize-aws-administration-with-iam-paths/) to scope created IAM User resource access.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="AWS Region" type="string" required>
|
||||
The AWS data center region.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="IAM User Permission Boundary" type="string" required>
|
||||
The IAM Policy ARN of the [AWS Permissions Boundary](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html) to attach to IAM users created in the role.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="AWS IAM Groups" type="string">
|
||||
The AWS IAM groups that should be assigned to the created users. Multiple values can be provided by separating them with commas
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="AWS Policy ARNs" type="string">
|
||||
The AWS IAM managed policies that should be attached to the created users. Multiple values can be provided by separating them with commas
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="AWS IAM Policy Document" type="string">
|
||||
The AWS IAM inline policy that should be attached to the created users. Multiple values can be provided by separating them with commas
|
||||
</ParamField>
|
||||
|
||||

|
||||
|
||||
</Step>
|
||||
<Step title="Click 'Submit'">
|
||||
After submitting the form, you will see a dynamic secret created in the dashboard.
|
||||
|
||||

|
||||
</Step>
|
||||
<Step title="Generate dynamic secrets">
|
||||
Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials.
|
||||
To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item.
|
||||
Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section.
|
||||
|
||||

|
||||

|
||||
|
||||
When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for.
|
||||
|
||||

|
||||
|
||||
<Tip>
|
||||
Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret in step 4.
|
||||
</Tip>
|
||||
|
||||
|
||||
Once you click the `Submit` button, a new secret lease will be generated and the credentials for it will be shown to you.
|
||||
|
||||

|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Audit or Revoke Leases
|
||||
Once you have created one or more leases, you will be able to access them by clicking on the respective dynamic secret item on the dashboard.
|
||||
This will allow you see the lease details and delete the lease ahead of its expiration time.
|
||||
|
||||

|
||||
|
||||
## Renew Leases
|
||||
To extend the life of the generated dynamic secret lease past its initial time to live, simply click on the **Renew** as illustrated below.
|
||||

|
||||
|
||||
<Warning>
|
||||
Lease renewals cannot exceed the maximum TTL set when configuring the dynamic secret
|
||||
</Warning>
|
@@ -1,13 +1,14 @@
|
||||
---
|
||||
title: "Overview"
|
||||
title: "Dynamic Secrets"
|
||||
sidebarTitle: "Overview"
|
||||
description: "Learn how to generate secrets dynamically on-demand."
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Contrary to static key-value secrets, which require manual input of data into the secure Infisical storage, dynamic secrets are generated on-demand upon access.
|
||||
Contrary to static key-value secrets, which require manual input of data into the secure Infisical storage, **dynamic secrets are generated on-demand upon access**.
|
||||
|
||||
Dynamic secrets are unique to every identity using them. Such secrets come are generated only at the moment they are retrieved, eliminating the possibility of theft or reuse by another identity. Thanks to Infisical's integrated revocation capabilities, dynamic secrets can be promptly invalidated post-use, significantly reducing their lifespan.
|
||||
**Dynamic secrets are unique to every identity using them**. Such secrets come are generated only at the moment they are retrieved, eliminating the possibility of theft or reuse by another identity. Thanks to Infisical's integrated revocation capabilities, dynamic secrets can be promptly invalidated post-use, significantly reducing their lifespan.
|
||||
|
||||
## Benefits of Dynamic Secrets
|
||||
|
||||
@@ -23,8 +24,12 @@ This approach offers several advantages in terms of security and management:
|
||||
|
||||
- **Scalability**: Dynamic secret management systems can scale more effectively to handle a large number of services and applications, as they automate much of the overhead associated with manual secret management.
|
||||
|
||||
Dynamic secrets are particularly useful in environments with stringent security requirements, such as cloud environments, distributed systems, and microservices architectures, where they help to manage database credentials, API keys, service tokens, and other types of secrets.
|
||||
Dynamic secrets are particularly useful in environments with stringent security requirements, such as cloud environments, distributed systems, and microservices architectures, where they help to manage database credentials, API keys, tokens, and other types of secrets.
|
||||
|
||||
## Infisical Dynamic Secret Templates
|
||||
|
||||
1. [PostgreSQL](./postgresql)
|
||||
2. [MySQL](./mysql)
|
||||
3. [Cassandra](./cassandra)
|
||||
4. [Oracle](./oracle)
|
||||
5. [AWS IAM](./aws-iam)
|
||||
|
@@ -26,13 +26,12 @@ This step also involves configuring an authentication method for it such as [Uni
|
||||
3. Authenticating the identity with the Infisical API based on the configured authentication method on it and receiving a short-lived access token back.
|
||||
4. Authenticating subsequent requests with the Infisical API using the short-lived access token.
|
||||
|
||||
|
||||
<Note>
|
||||
Currently, identities can only be used to make authenticated requests to the Infisical API, SDKs, Terraform, Kubernetes Operator, and Infisical Agent. They do not work with clients such as CLI, Ansible look up plugin, etc.
|
||||
|
||||
Machine Identity support for the rest of the clients is planned to be released in the current quarter.
|
||||
</Note>
|
||||
|
||||
</Note>
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
@@ -43,8 +42,16 @@ To interact with various resources in Infisical, Machine Identities are able to
|
||||
## FAQ
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Can I use machine identities with the CLI?">
|
||||
|
||||
Yes - Identities can be used with the CLI.
|
||||
|
||||
You can learn more about how to do this in the CLI quickstart [here](/cli/usage).
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="What is the difference between an identity and service token?">
|
||||
A service token is a project-level authentication method that is being phased out in favor of identities.
|
||||
A service token is a project-level authentication method that is being deprecated in favor of identities. The service token method will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
Amongst many differences, identities provide broader access over the Infisical API, utilizes the same
|
||||
permission system as user identities, and come with a significantly larger number of configurable authentication and security features.
|
||||
|
@@ -17,7 +17,6 @@ Upon being added to an organization and projects, users assume a certain set of
|
||||
|
||||
To interact with various resources in Infisical, users are able to utilize a number of authentication methods:
|
||||
- **Email & Password**: the most common authentication method that is used for authentication into Web Dashboard and Infisical CLI. It is recommended to utilize [Multi-factor Authentication](/documentation/platform/mfa) in addition to it.
|
||||
- **Service Tokens**: Service tokens allow users authenticate into CLI and other clients under their own identity. For the majority of use cases, it is not a recommended approach. Instead, it is often a good idea to utilize [Machine Identities](./machine-identities) with [Universal Authentication](/documentation/platform/identities/universal-auth).
|
||||
- **SSO**: Infisical natively integrates with a number of SSO identity providers like [Google](/documentation/platform/sso/google), [GitHub](/documentation/platform/sso/github), and [GitLab](/documentation/platform/sso/gitlab).
|
||||
- **SAML SSO**: It is also possible to set up SAML SSO integration with identity providers like [Okta](/documentation/platform/sso/okta), [Microsoft Entra ID](/documentation/platform/sso/azure) (formerly known as Azure AD), [JumpCloud](/documentation/platform/sso/jumpcloud), [Google](/documentation/platform/sso/google-saml), and more.
|
||||
- **LDAP**: For organizations with more advanced needs, Infisical also provides user authentication with [LDAP](/documentation/platform/ldap/overview) that includes a number of LDAP providers.
|
||||
|
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: "IP Allowlisting"
|
||||
description: "Restrict access to your secrets in Infisical using trusted IPs"
|
||||
---
|
||||
|
||||
<Warning>
|
||||
IP allowlisting at the project-level is being replaced with IP allowlisting at the token-level now available with the Service Token V3 authentication method.
|
||||
|
||||
Instead of providing trusted IPs (specific IPs and CIDR ranges) to be applied across all service tokens,
|
||||
you can now specify trusted IPs at the token-level.
|
||||
|
||||
</Warning>
|
||||
<Info>
|
||||
Note that IP Allowlisting is a paid feature.
|
||||
|
||||
If you're using Infisical Cloud, then it is available under the **Pro Tier**. If you're self-hosting Infisical,
|
||||
then you should contact sales@infisical.com to purchase an enterprise license to use it.
|
||||
</Info>
|
||||
|
||||
Projects in Infisical can be configured to restrict client access to specific IP addresses or CIDR ranges. This applies to any client using service tokens and
|
||||
can be useful, for example, for limiting access to traffic coming from corporate networks.
|
||||
|
||||
By default, each project is initialized with the `0.0.0.0/0` entry, representing all possible IPv4 addresses.
|
||||
For enhanced security, we strongly recommend replacing the default entry with your client IPs to tighten access to your secrets.
|
||||
|
||||
<Note>
|
||||
You must be a project `admin` to manage your project's IP whitelist.
|
||||
</Note>
|
||||
|
||||

|
||||
|
||||
## Creating a trusted IP entry
|
||||
|
||||
To create a trusted IP entry, head over to the **IP Whitelist** tab in your project. When creating an entry,
|
||||
you can specify either a specific IP address like `192.0.2.1` or a CIDR range like `2001:db8::/32`; both IPv4 and IPv6
|
||||
formats are accepted.
|
||||
|
||||

|
@@ -19,7 +19,7 @@ This means that updating the value of a base secret propagates directly to other
|
||||
|
||||

|
||||
|
||||
Since secret referencing works by reconstructing values back on the client side, the client, be it a user or service token, fetching back secrets
|
||||
Since secret referencing works by reconstructing values back on the client side, the client, be it a user, service token, or a machine identity, fetching back secrets
|
||||
must be permissioned access to all base and dependent secrets.
|
||||
|
||||
For example, to access some secret `A` whose values depend on secrets `B` and `C` from different scopes, a client must have `read` access to the scopes of secrets `A`, `B`, and `C`.
|
||||
|
@@ -5,7 +5,7 @@ description: "Learn how secret versioning works in Infisical."
|
||||
|
||||
Every time a secret change is persformed, a new version of the same secret is created.
|
||||
|
||||
Such versions can be accessed visually by opening up the [secret sidebar](/documentation/platform/project#drawer) (as seen below) or [retrived via API](/api-reference/endpoints/secrets/read)
|
||||
Such versions can be accessed visually by opening up the [secret sidebar](/documentation/platform/project#drawer) (as seen below) or [retrieved via API](/api-reference/endpoints/secrets/read)
|
||||
by specifying the `version` query parameter.
|
||||
|
||||

|
||||
|
@@ -3,6 +3,13 @@ title: "Service Token"
|
||||
description: "Infisical service tokens allow users to programmatically interact with Infisical."
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
||||
They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
</Warning>
|
||||
|
||||
Service tokens are authentication credentials that services can use to access designated endpoints in the Infisical API to manage project resources like secrets.
|
||||
Each service token can be provisioned scoped access to select environment(s) and path(s) within them.
|
||||
|
||||
@@ -44,7 +51,8 @@ In the above screenshot, you can see that we are creating a token token with `re
|
||||
of the `/common` path within the development environment of the project; the token expires in 6 months and can be used from any IP address.
|
||||
|
||||
<Note>
|
||||
For a deeper understanding of service tokens, it is recommended to read [this guide](https://infisical.com/docs/internals/service-tokens).
|
||||
For a deeper understanding of service tokens, it is recommended to read [this
|
||||
guide](https://infisical.com/docs/internals/service-tokens).
|
||||
</Note>
|
||||
|
||||
**FAQ**
|
||||
@@ -58,6 +66,7 @@ For a deeper understanding of service tokens, it is recommended to read [this gu
|
||||
- You are attempting to access a `/raw` secrets endpoint that requires your project to disable E2EE.
|
||||
- (If using ST V3) The service token has not been activated yet.
|
||||
- (If using ST V3) The service token is being used from an untrusted IP.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Can you provide examples for using glob patterns?">
|
||||
1. `/**`: This pattern matches all folders at any depth in the directory structure. For example, it would match folders like `/folder1/`, `/folder1/subfolder/`, and so on.
|
||||
@@ -67,5 +76,6 @@ For a deeper understanding of service tokens, it is recommended to read [this gu
|
||||
3. `/*/*`: This pattern matches all subfolders at a depth of two levels in the current directory. It does not match any folders at a shallower or deeper level. For example, it would match folders like `/folder1/subfolder/`, `/folder2/subfolder/`, but not `/folder1/` or `/folder1/subfolder/subsubfolder/`.
|
||||
|
||||
4. `/folder1/*`: This pattern matches all immediate subfolders within the `/folder1/` directory. It does not match any folders outside of `/folder1/`, nor does it match any subfolders within those immediate subfolders. For example, it would match folders like `/folder1/subfolder1/`, `/folder1/subfolder2/`, but not `/folder2/subfolder/`.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 160 KiB |
BIN
docs/images/integrations/jenkins/jenkins_10_identity.png
Normal file
After Width: | Height: | Size: 268 KiB |
BIN
docs/images/integrations/jenkins/jenkins_11_identity.png
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
docs/images/integrations/jenkins/jenkins_4_identity_id.png
Normal file
After Width: | Height: | Size: 184 KiB |
BIN
docs/images/integrations/jenkins/jenkins_4_identity_secret.png
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
docs/images/integrations/jenkins/jenkins_5_identity.png
Normal file
After Width: | Height: | Size: 210 KiB |
BIN
docs/images/integrations/jenkins/jenkins_9_identity.png
Normal file
After Width: | Height: | Size: 229 KiB |
After Width: | Height: | Size: 126 KiB |
After Width: | Height: | Size: 257 KiB |
BIN
docs/images/platform/audit-log-streams/data-create-api-key.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
docs/images/platform/audit-log-streams/data-dog-api-key.png
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
docs/images/platform/audit-log-streams/datadog-api-sidebar.png
Normal file
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 38 KiB |
BIN
docs/images/platform/audit-log-streams/stream-create.png
Normal file
After Width: | Height: | Size: 361 KiB |
BIN
docs/images/platform/audit-log-streams/stream-inputs.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
docs/images/platform/audit-log-streams/stream-list.png
Normal file
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 96 KiB |
BIN
docs/images/platform/dynamic-secrets/lease-values-aws-iam.png
Normal file
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 722 KiB |
@@ -6,18 +6,157 @@ description: "How to effectively and securely manage secrets in Jenkins using In
|
||||
**Objective**: Fetch secrets from Infisical to Jenkins pipelines
|
||||
|
||||
In this guide, we'll outline the steps to deliver secrets from Infisical to Jenkins via the Infisical CLI.
|
||||
At a high level, the Infisical CLI will be executed within your build environment and use a service token to authenticate with Infisical.
|
||||
At a high level, the Infisical CLI will be executed within your build environment and use a machine identity to authenticate with Infisical.
|
||||
This token must be added as a Jenkins Credential and then passed to the Infisical CLI as an environment variable, enabling it to access and retrieve secrets within your workflows.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Set up and add secrets to [Infisical](https://app.infisical.com).
|
||||
- Create a [machine identity](/documentation/platform/identities/machine-identities) (Recommended), or a service token in Infisical.
|
||||
- You have a working Jenkins installation with the [credentials plugin](https://plugins.jenkins.io/credentials/) installed.
|
||||
- You have the [Infisical CLI](/cli/overview) installed on your Jenkins executor nodes or container images.
|
||||
|
||||
<Tabs>
|
||||
|
||||
<Tab title="Machine Identity (Recommended)">
|
||||
## Add Infisical Machine Identity to Jenkins
|
||||
|
||||
After setting up your project in Infisical and installing the Infisical CLI to the environment where your Jenkins builds will run, you will need to add the Infisical Machine Identity to Jenkins.
|
||||
|
||||
To generate a Infisical machine identity, follow the guide [here](/documentation/platform/identities/machine-identities).
|
||||
Once you have generated the token, navigate to **Manage Jenkins > Manage Credentials** in your Jenkins instance.
|
||||
|
||||

|
||||
|
||||
Click on the credential store you want to store the Infisical Machine Identity in. In this case, we're using the default Jenkins global store.
|
||||
|
||||
<Info>
|
||||
Each of your projects will have a different `INFISICAL_TOKEN`.
|
||||
As a result, it may make sense to spread these out into separate credential domains depending on your use case.
|
||||
</Info>
|
||||
|
||||

|
||||
|
||||
Now, click Add Credentials.
|
||||
|
||||

|
||||
|
||||
Choose **Secret text** for the **Kind** option from the dropdown list and enter the Infisical Service Token in the **Secret** field.
|
||||
Although the **ID** can be any value, we'll set it to `infisical-machine-identity-client-id` and `infisical-machine-identity-client-secret` for the sake of this guide.
|
||||
The description is optional and can be any text you prefer.
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
When you're done, you should see two credentials similar to the one below:
|
||||
|
||||

|
||||
|
||||
|
||||
## Use Infisical in a Freestyle Project
|
||||
|
||||
To fetch secrets with Infisical in a Freestyle Project job, you'll need to expose the credential you created above as an environment variable to the Infisical CLI.
|
||||
To do so, first click **New Item** from the dashboard navigation sidebar:
|
||||
|
||||

|
||||
|
||||
Enter the name of the job, choose the **Freestyle Project** option, and click **OK**.
|
||||
|
||||

|
||||
|
||||
Scroll down to the **Build Environment** section and enable the **Use secret text(s) or file(s)** option. Then click **Add** under the **Bindings** section and choose **Secret text** from the dropdown menu.
|
||||
|
||||

|
||||
|
||||
Enter `INFISICAL_MACHINE_IDENTITY_CLIENT_ID` in the **Variable** field for the client ID, and `INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET` for the client secret. Then click the **Specific credentials** option from the Credentials section and select the credentials you created earlier.
|
||||
In this case, we saved it as `Infisical Machine Identity Client ID` and `Infisical Machine Identity Client Secret` so we'll choose those from the dropdown menu.
|
||||
|
||||
Make sure to add bindings for both the client ID and the client secret.
|
||||
|
||||

|
||||
|
||||
Scroll down to the **Build** section and choose **Execute shell** from the **Add build step** menu.
|
||||
|
||||

|
||||
|
||||
In the command field, you can now use the Infisical CLI to fetch secrets.
|
||||
The example command below will print the secrets using the service token passed as a credential. When done, click **Save**.
|
||||
|
||||
```bash
|
||||
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=$INFISICAL_MACHINE_IDENTITY_CLIENT_ID --client-secret=$INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET --silent --plain)
|
||||
infisical secrets --env dev --projectId=<your-project-id>
|
||||
```
|
||||
|
||||

|
||||
|
||||
Finally, click **Build Now** from the navigation sidebar to run your new job.
|
||||
|
||||
<Info>
|
||||
Running into issues? Join Infisical's [community Slack](https://infisical.com/slack) for quick support.
|
||||
</Info>
|
||||
|
||||
|
||||
|
||||
## Use Infisical in a Jenkins Pipeline
|
||||
|
||||
To fetch secrets using Infisical in a Pipeline job, you'll need to expose the Jenkins credential you created above as an environment variable.
|
||||
To do so, click **New Item** from the dashboard navigation sidebar:
|
||||
|
||||

|
||||
|
||||
Enter the name of the job, choose the **Pipeline** option, and click OK.
|
||||
|
||||

|
||||
|
||||
Scroll down to the **Pipeline** section, paste the following into the **Script** field, and click **Save**.
|
||||
|
||||
```
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
MACHINE_IDENTITY_CLIENT_ID = credentials('infisical-machine-identity-client-id')
|
||||
MACHINE_IDENTITY_CLIENT_SECRET = credentials('infisical-machine-identity-client-secret')
|
||||
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Run Infisical') {
|
||||
steps {
|
||||
sh("export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=${MACHINE_IDENTITY_CLIENT_ID} --client-secret=${MACHINE_IDENTITY_CLIENT_SECRET} --silent --plain)")
|
||||
sh("infisical secrets --env=dev --path=/ --projectId=<your-project-id>")
|
||||
|
||||
// doesn't work
|
||||
// sh("docker run --rm test-container infisical secrets --projectId=<your-project-id>")
|
||||
|
||||
// works
|
||||
// sh("docker run -e INFISICAL_TOKEN=${INFISICAL_TOKEN} --rm test-container infisical secrets --env=dev --path=/ --projectId=<your-project-id>")
|
||||
|
||||
// doesn't work
|
||||
// sh("docker-compose up -d")
|
||||
|
||||
// works
|
||||
// sh("INFISICAL_TOKEN=${INFISICAL_TOKEN} docker-compose up -d")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Service Token (Deprecated)">
|
||||
## Add Infisical Service Token to Jenkins
|
||||
|
||||
<Warning>
|
||||
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
||||
They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
</Warning>
|
||||
|
||||
After setting up your project in Infisical and installing the Infisical CLI to the environment where your Jenkins builds will run, you will need to add the Infisical Service Token to Jenkins.
|
||||
|
||||
To generate a Infisical service token, follow the guide [here](/documentation/platform/token).
|
||||
@@ -134,6 +273,10 @@ pipeline {
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
</Tabs>
|
||||
|
||||
The example provided above serves as an initial guide. It shows how Jenkins adds the `INFISICAL_TOKEN` environment variable, which is configured in the pipeline, into the shell for executing commands.
|
||||
There may be instances where this doesn't work as expected in the context of running Docker commands.
|
||||
However, the list of working examples should provide some insight into how this can be handled properly.
|
||||
|
@@ -4,6 +4,7 @@ description: "Learn how to sync secrets from Infisical to AWS Amplify."
|
||||
---
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Infisical Cloud account
|
||||
- Add the secrets you wish to sync to Amplify to [Infisical Cloud](https://app.infisical.com)
|
||||
|
||||
@@ -13,6 +14,61 @@ There are many approaches to sync secrets stored within Infisical to AWS Amplify
|
||||
|
||||
This approach enables you to fetch secrets from Infisical during Amplify build time.
|
||||
|
||||
<Tabs>
|
||||
|
||||
<Tab title="Machine Identity (Recommended)">
|
||||
<Steps>
|
||||
<Step title="Create a machine identity">
|
||||
Create a machine identtiy and connect it to your Infisical project. You can read more about how to use machine identities [here](/documentation/platform/identities/machine-identities). The machine identity will allow you to authenticate and fetch secrets from Infisical.
|
||||
</Step>
|
||||
|
||||
<Step title="Set the machine identity client ID and client secret as Amplify environment variables">
|
||||

|
||||
1. In the Amplify console, choose App Settings, and then select Environment variables.
|
||||
2. In the Environment variables section, select Manage variables.
|
||||
3. Under the first Variable enter `INFISICAL_MACHINE_IDENTITY_CLIENT_ID`, and for the value, enter the client ID of the machine identity you created in the previous step.
|
||||
4. Under the second Variable enter `INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET`, and for the value, enter the client secret of the machine identity you created in the previous step.
|
||||
5. Click save.
|
||||
</Step>
|
||||
|
||||
<Step title="Install Infisical CLI to the Amplify build step">
|
||||
In the prebuild phase, add the command in AWS Amplify to install the Infisical CLI.
|
||||
|
||||
```yaml
|
||||
build:
|
||||
phases:
|
||||
preBuild:
|
||||
commands:
|
||||
- sudo curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.rpm.sh' | sudo -E bash
|
||||
- sudo yum -y install infisical
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Modify the build command">
|
||||
You can now pull secrets from Infisical using the CLI and save them as a `.env` file. To do this, modify the build commands.
|
||||
|
||||
```yaml
|
||||
build:
|
||||
phases:
|
||||
build:
|
||||
commands:
|
||||
- INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=${INFISICAL_MACHINE_IDENTITY_CLIENT_ID} --client-secret=${INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET} --silent --plain)
|
||||
- infisical export --format=dotenv > .env
|
||||
- <rest of the commands>
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Service Token (Deprecated)">
|
||||
|
||||
<Warning>
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
||||
They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
</Warning>
|
||||
|
||||
<Steps>
|
||||
<Step title="Generate a service token">
|
||||
Go to your project settings in the Infisical dashboard to generate a [service token](/documentation/platform/token). This service token will allow you to authenticate and fetch secrets from Infisical. Once you have created a service token with the required permissions, you’ll need to provide the token to the CLI installed in your Docker container.
|
||||
@@ -71,6 +127,11 @@ At high level, you begin by using Infisical's AWS SSM Parameter Store integratio
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Info>
|
||||
Accessing an environment secret during a build is similar to accessing environment variables, except that environment secrets are stored in `process.env.secrets` as a JSON string.
|
||||
Accessing an environment secret during a build is similar to accessing
|
||||
environment variables, except that environment secrets are stored in
|
||||
`process.env.secrets` as a JSON string.
|
||||
</Info>
|
||||
|
@@ -30,13 +30,18 @@ Prerequisites:
|
||||
"ssm:DeleteParameter",
|
||||
"ssm:GetParametersByPath",
|
||||
"ssm:DeleteParameters",
|
||||
"ssm:AddTagsToResource" // if you need to add tags to secrets
|
||||
"ssm:AddTagsToResource", // if you need to add tags to secrets
|
||||
"kms:ListKeys", // if you need to specify the KMS key
|
||||
"kms:ListAliases", // if you need to specify the KMS key
|
||||
"kms:Encrypt", // if you need to specify the KMS key
|
||||
"kms:Decrypt" // if you need to specify the KMS key
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
<Step title="Authorize Infisical for AWS Parameter store">
|
||||
Obtain a AWS access key ID and secret access key for your IAM user in IAM > Users > User > Security credentials > Access keys
|
||||
@@ -59,6 +64,7 @@ Prerequisites:
|
||||
breaks E2EE, it's necessary for Infisical to sync the environment variables to
|
||||
the cloud platform.
|
||||
</Info>
|
||||
|
||||
</Step>
|
||||
<Step title="Start integration">
|
||||
Select which Infisical environment secrets you want to sync to which AWS Parameter Store region and indicate the path for your secrets. Then, press create integration to start syncing secrets to AWS Parameter Store.
|
||||
@@ -72,6 +78,6 @@ Prerequisites:
|
||||
secret like `TEST` to be stored as `/[project_name]/[environment]/TEST` in AWS
|
||||
Parameter Store.
|
||||
</Tip>
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
|
@@ -31,7 +31,9 @@ Prerequisites:
|
||||
"secretsmanager:UpdateSecret",
|
||||
"secretsmanager:TagResource", // if you need to add tags to secrets
|
||||
"kms:ListKeys", // if you need to specify the KMS key
|
||||
"kms:ListAliases" // if you need to specify the KMS key
|
||||
"kms:ListAliases", // if you need to specify the KMS key
|
||||
"kms:Encrypt", // if you need to specify the KMS key
|
||||
"kms:Decrypt" // if you need to specify the KMS key
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
|
@@ -34,7 +34,9 @@ Set up the Infisical provider by specifying the `host` and `service_token`. Repl
|
||||
```hcl main.tf
|
||||
provider "infisical" {
|
||||
host = "https://app.infisical.com" # Only required if using self hosted instance of Infisical, default is https://app.infisical.com
|
||||
service_token = "<>" # Get token https://infisical.com/docs/documentation/platform/token
|
||||
client_id = "<>"
|
||||
client_secret = "<>"
|
||||
service_token = "<>" # DEPRECATED, USE MACHINE IDENTITY AUTH INSTEAD
|
||||
}
|
||||
```
|
||||
|
||||
@@ -54,6 +56,7 @@ Use the `infisical_secrets` data source to fetch your secrets. In this block, yo
|
||||
data "infisical_secrets" "my-secrets" {
|
||||
env_slug = "dev"
|
||||
folder_path = "/some-folder/another-folder"
|
||||
workspace_id = "your-project-id"
|
||||
}
|
||||
```
|
||||
|
||||
|
@@ -11,9 +11,69 @@ Prerequisites:
|
||||
|
||||
Follow this [guide](./docker) to configure the Infisical CLI for each service that you wish to inject environment variables into; you'll have to update the Dockerfile of each service.
|
||||
|
||||
## Generate service token
|
||||
<Tabs>
|
||||
<Tab title="Machine Identity (Recommended)">
|
||||
### Generate and configure machine identity
|
||||
Generate a machine identity for each service you want to inject secrets into. You can do this by following the steps in the [Machine Identity](/documentation/platform/identities/machine-identities) guide.
|
||||
|
||||
Generate a unique [Infisical Token](/documentation/platform/token) for each service.
|
||||
### Set the machine identity client ID and client secret as environment variables
|
||||
For each service you want to inject secrets into, set two environment variable called `INFISICAL_MACHINE_IDENTITY_CLIENT_ID`, and `INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET` equal to the client ID and client secret of the machine identity(s) you created in the previous step.
|
||||
|
||||
In the example below, we set two sets of client ID and client secret for the services.
|
||||
|
||||
For the web service we set `INFISICAL_MACHINE_IDENTITY_CLIENT_ID_FOR_WEB` and `INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET_FOR_WEB` as the client ID and client secret respectively.
|
||||
|
||||
For the API service we set `INFISICAL_MACHINE_IDENTITY_CLIENT_ID_FOR_API` and `INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET_FOR_API` as the client ID and client secret respectively.
|
||||
|
||||
```yaml
|
||||
# Example Docker Compose file
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
image: example-service-1
|
||||
environment:
|
||||
- INFISICAL_MACHINE_IDENTITY_CLIENT_ID=${INFISICAL_MACHINE_IDENTITY_CLIENT_ID_FOR_WEB}
|
||||
- INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET=${INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET_FOR_WEB}
|
||||
|
||||
api:
|
||||
build: .
|
||||
image: example-service-2
|
||||
environment:
|
||||
- INFISICAL_MACHINE_IDENTITY_CLIENT_ID=${INFISICAL_MACHINE_IDENTITY_CLIENT_ID_FOR_API}
|
||||
- INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET=${INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET_FOR_API}
|
||||
|
||||
```
|
||||
|
||||
### Export shell variables
|
||||
Next, set the shell variables you defined in your compose file. This can be done manually or via your CI/CD environment. Once done, it will be used to populate the corresponding `INFISICAL_MACHINE_IDENTITY_CLIENT_ID` and `INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET` in your Docker Compose file.
|
||||
|
||||
```bash
|
||||
#Example
|
||||
|
||||
# Token refers to the token we generated in step 2 for this service
|
||||
export INFISICAL_MACHINE_IDENTITY_CLIENT_ID_FOR_WEB=<client_id>
|
||||
export INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET_FOR_WEB=<client_secret>
|
||||
|
||||
# Token refers to the token we generated in step 2 for this service
|
||||
export INFISICAL_MACHINE_IDENTITY_CLIENT_ID_FOR_API=<client_id>
|
||||
export INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET_FOR_API=<client_secret>
|
||||
|
||||
# Then run your compose file in the same terminal.
|
||||
docker-compose ...
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Service Token (Deprecated)">
|
||||
|
||||
<Warning>
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
||||
They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
</Warning>
|
||||
|
||||
## Generate service token
|
||||
Generate a unique [Service Token](/documentation/platform/token) for each service.
|
||||
|
||||
## Feed service token to your Docker Compose file
|
||||
|
||||
@@ -54,3 +114,6 @@ export INFISICAL_TOKEN_FOR_API=<token>
|
||||
# Then run your compose file in the same terminal.
|
||||
docker-compose ...
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
@@ -10,8 +10,11 @@ For this method to function as expected, you must have a bash shell (for process
|
||||
|
||||
## 1. Authentication
|
||||
|
||||
If you are already logged in via the CLI you can skip this step. Otherwise, head to your project settings in Infisical Cloud to generate an [Infisical Token](/documentation/platform/token). The service token will allow you to authenticate and fetch secrets from Infisical.
|
||||
Once you have created a service token with the required permissions, you'll need to feed the token to the CLI.
|
||||
If you are already logged in via the CLI you can skip this step. Otherwise, head to your organization settings in Infisical Cloud to create a [Machine Identity](../../documentation/platform/identities/machine-identities). The machine identity will allow you to authenticate and fetch secrets from Infisical.
|
||||
Once you have created a machine identity with the required permissions, you'll need to feed the token to the CLI.
|
||||
<Info>
|
||||
Please note that we highly recommend using `infisical login` for local development.
|
||||
</Info>
|
||||
|
||||
#### Pass as flag
|
||||
You may use the --token flag to set the token
|
||||
@@ -27,8 +30,14 @@ The CLI is configured to look for an environment variable named `INFISICAL_TOKEN
|
||||
export INFISICAL_TOKEN=<>
|
||||
```
|
||||
|
||||
You can use the `infisical login --method=universal-auth` command to directly obtain a universal auth access token and set it as an environment variable.
|
||||
|
||||
```bash
|
||||
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=<your-client-id> --client-secret=<your-client-secret> --silent --plain)
|
||||
```
|
||||
|
||||
<Warning>
|
||||
In production scenarios, please to avoid using the `infisical login` command and instead use a [service token](/documentation/platform/token).
|
||||
In production scenarios, please to avoid using the `infisical login` command and instead use a [machine identity](../../documentation/platform/identities/machine-identities).
|
||||
</Warning>
|
||||
|
||||
## 2. Run your docker command with Infisical
|
||||
|
@@ -41,6 +41,54 @@ This is achieved by installing the Infisical CLI into your docker image and modi
|
||||
|
||||
Starting your service with the Infisical CLI pulls your secrets from Infisical and injects them into your service.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Machine Identity (Recommended)">
|
||||
```dockerfile
|
||||
CMD ["infisical", "run", "--projectId", "<your-project-id>", "--", "[your service start command]"]
|
||||
|
||||
# example with single single command
|
||||
|
||||
CMD ["infisical", "run", "--projectId", "<your-project-id>", "--", "npm", "run", "start"]
|
||||
|
||||
# example with multiple commands
|
||||
|
||||
CMD ["infisical", "run", "--projectId", "<your-project-id>", "--command", "npm run start && ..."]
|
||||
|
||||
````
|
||||
|
||||
<Steps>
|
||||
<Step title="Generate a machine identity">
|
||||
Generate a machine identity for your project by following the steps in the [Machine Identity](/documentation/platform/identities/machine-identities) guide. The machine identity will allow you to authenticate and fetch secrets from Infisical.
|
||||
</Step>
|
||||
<Step title="Obtain an access token for the machine identity">
|
||||
Obtain an access token for the machine identity by running the following command:
|
||||
```bash
|
||||
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=<your-client-id> --client-secret=<your-client-secret> --plain --silent)
|
||||
```
|
||||
|
||||
<Info>
|
||||
Please note that the access token has a limited lifespan. The `infisical token renew` command can be used to renew the token if needed.
|
||||
</Info>
|
||||
</Step>
|
||||
<Step title="Feed the access token to the docker container">
|
||||
The last step is to give the Infisical CLI installed in your Docker container access to the access token. This will allow the CLI to fetch and inject the secrets into your application.
|
||||
|
||||
To feed the access token to the container, use the INFISICAL_TOKEN environment variable as shown below.
|
||||
|
||||
```bash
|
||||
docker run --env INFISICAL_TOKEN=$INFISICAL_TOKEN [DOCKER-IMAGE]...
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
</Tab>
|
||||
<Tab title="Service Token (Deprecated)">
|
||||
<Warning>
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
||||
They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
</Warning>
|
||||
```dockerfile
|
||||
CMD ["infisical", "run", "--", "[your service start command]"]
|
||||
|
||||
@@ -49,15 +97,15 @@ CMD ["infisical", "run", "--", "npm", "run", "start"]
|
||||
|
||||
# example with multiple commands
|
||||
CMD ["infisical", "run", "--command", "npm run start && ..."]
|
||||
```
|
||||
|
||||
## Generate a service token
|
||||
````
|
||||
|
||||
<Steps>
|
||||
<Step title="Generate a service token">
|
||||
Head to your project settings in the Infisical dashboard to generate an [service token](/documentation/platform/token).
|
||||
This service token will allow you to authenticate and fetch secrets from Infisical.
|
||||
Once you have created a service token with the required permissions, you’ll need to feed the token to the CLI installed in your docker container.
|
||||
|
||||
## Feed service token to docker container
|
||||
</Step>
|
||||
<Step title="Feed service token to docker container">
|
||||
The last step is to give the Infisical CLI installed in your Docker container access to the service token. This will allow the CLI to fetch and inject the secrets into your application.
|
||||
|
||||
To feed the service token to the container, use the INFISICAL_TOKEN environment variable as shown below.
|
||||
@@ -65,3 +113,8 @@ To feed the service token to the container, use the INFISICAL_TOKEN environment
|
||||
```bash
|
||||
docker run --env INFISICAL_TOKEN=[token] [DOCKER-IMAGE]...
|
||||
```
|
||||
</Step>
|
||||
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
@@ -1,11 +1,10 @@
|
||||
---
|
||||
title: 'Kubernetes'
|
||||
title: "Kubernetes"
|
||||
description: "How to use Infisical to inject secrets into Kubernetes clusters."
|
||||
---
|
||||
|
||||

|
||||
|
||||
|
||||
The Infisical Secrets Operator is a Kubernetes controller that retrieves secrets from Infisical and stores them in a designated cluster.
|
||||
It uses an `InfisicalSecret` resource to specify authentication and storage methods.
|
||||
The operator continuously updates secrets and can also reload dependent deployments automatically.
|
||||
@@ -42,7 +41,6 @@ The operator can be install via [Helm](https://helm.sh) or [kubectl](https://git
|
||||
For production deployments, it is highly recommended to set the version of the Kubernetes operator manually instead of pointing to the latest version.
|
||||
Doing so will help you avoid accidental updates to the newest release which may introduce unintended breaking changes. View all application versions [here](https://hub.docker.com/r/infisical/kubernetes-operator/tags).
|
||||
|
||||
|
||||
The command below will install the most recent version of the Kubernetes operator.
|
||||
However, to set the version manually, download the manifest and set the image tag version of `infisical/kubernetes-operator` according to your desired version.
|
||||
|
||||
@@ -51,10 +49,12 @@ The operator can be install via [Helm](https://helm.sh) or [kubectl](https://git
|
||||
```
|
||||
kubectl apply -f https://raw.githubusercontent.com/Infisical/infisical/main/k8-operator/kubectl-install/install-secrets-operator.yaml
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Sync Infisical Secrets to your cluster
|
||||
|
||||
Once you have installed the operator to your cluster, you'll need to create a `InfisicalSecret` custom resource definition (CRD).
|
||||
|
||||
```yaml example-infisical-secret-crd.yaml
|
||||
@@ -81,6 +81,7 @@ spec:
|
||||
secretName: universal-auth-credentials
|
||||
secretNamespace: default
|
||||
|
||||
# Service tokens are deprecated and will be removed in the near future. Please use Machine Identities for authenticating with Infisical.
|
||||
serviceToken:
|
||||
serviceTokenSecretReference:
|
||||
secretName: service-token
|
||||
@@ -95,6 +96,7 @@ spec:
|
||||
creationPolicy: "Orphan" ## Owner | Orphan (default)
|
||||
# secretType: kubernetes.io/dockerconfigjson
|
||||
```
|
||||
|
||||
### InfisicalSecret CRD properties
|
||||
|
||||
<Accordion title="hostAPI">
|
||||
@@ -112,16 +114,19 @@ spec:
|
||||
```
|
||||
|
||||
Make sure to replace `<backend-svc-name>` and `<namespace>` with the appropriate values for your backend service and namespace.
|
||||
|
||||
</Accordion>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="resyncInterval">
|
||||
This property defines the time in seconds between each secret re-sync from Infisical. Shorter time between re-syncs will require higher rate limits only available on paid plans.
|
||||
Default re-sync interval is every 1 minute.
|
||||
This property defines the time in seconds between each secret re-sync from
|
||||
Infisical. Shorter time between re-syncs will require higher rate limits only
|
||||
available on paid plans. Default re-sync interval is every 1 minute.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="authentication">
|
||||
This block defines the method that will be used to authenticate with Infisical so that secrets can be fetched
|
||||
This block defines the method that will be used to authenticate with Infisical
|
||||
so that secrets can be fetched
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="authentication.universalAuth">
|
||||
@@ -145,15 +150,20 @@ Default re-sync interval is every 1 minute.
|
||||
<Step title="Add reference for the Kubernetes secret containing the identity credentials">
|
||||
Once the secret is created, add the `secretName` and `secretNamespace` of the secret that was just created under `authentication.universalAuth.credentialsRef` field in the InfisicalSecret resource.
|
||||
</Step>
|
||||
|
||||
</Steps>
|
||||
|
||||
|
||||
{" "}
|
||||
|
||||
<Info>
|
||||
Make sure to also populate the `secretsScope` field with the project slug _`projectSlug`_, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below.
|
||||
Make sure to also populate the `secretsScope` field with the project slug
|
||||
_`projectSlug`_, environment slug _`envSlug`_, and secrets path
|
||||
_`secretsPath`_ that you want to fetch secrets from. Please see the example
|
||||
below.
|
||||
</Info>
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
@@ -171,9 +181,17 @@ Default re-sync interval is every 1 minute.
|
||||
secretNamespace: default # <-- namespace of the Kubernetes secret that stores our machine identity credentials
|
||||
...
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="authentication.serviceToken">
|
||||
<Warning>
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
||||
They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
</Warning>
|
||||
|
||||
The service token required to authenticate with Infisical needs to be stored in a Kubernetes secret. This block defines the reference to the name and namespace of secret that stores this service token.
|
||||
Follow the instructions below to create and store the service token in a Kubernetes secrets and reference it in your CRD.
|
||||
|
||||
@@ -194,11 +212,16 @@ Default re-sync interval is every 1 minute.
|
||||
|
||||
Once the secret is created, add the name and namespace of the secret that was just created under `authentication.serviceToken.serviceTokenSecretReference` field in the InfisicalSecret resource.
|
||||
|
||||
{" "}
|
||||
|
||||
<Info>
|
||||
Make sure to also populate the `secretsScope` field with the, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below.
|
||||
Make sure to also populate the `secretsScope` field with the, environment slug
|
||||
_`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets
|
||||
from. Please see the example below.
|
||||
</Info>
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
@@ -215,6 +238,7 @@ Default re-sync interval is every 1 minute.
|
||||
secretsPath: <secrets-path> # Root is "/"
|
||||
...
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="managedSecretReference">
|
||||
@@ -239,11 +263,13 @@ Creation polices allow you to control whether or not owner references should be
|
||||
This is useful for tools such as ArgoCD, where every resource requires an owner reference; otherwise, it will be pruned automatically.
|
||||
|
||||
#### Available options
|
||||
|
||||
- `Orphan` (default)
|
||||
- `Owner`
|
||||
|
||||
<Tip>
|
||||
When creation policy is set to `Owner`, the `InfisicalSecret` CRD must be in the same namespace as where the managed kubernetes secret.
|
||||
When creation policy is set to `Owner`, the `InfisicalSecret` CRD must be in
|
||||
the same namespace as where the managed kubernetes secret.
|
||||
</Tip>
|
||||
|
||||
</Accordion>
|
||||
@@ -275,8 +301,7 @@ This would result in the following managed secret to be created:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
...
|
||||
data: ...
|
||||
kind: Secret
|
||||
metadata:
|
||||
annotations:
|
||||
@@ -288,10 +313,11 @@ metadata:
|
||||
namespace: default
|
||||
type: Opaque
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
|
||||
### Apply the Infisical CRD to your cluster
|
||||
|
||||
Once you have configured the Infisical CRD with the required fields, you can apply it to your cluster.
|
||||
After applying, you should notice that the managed secret has been created in the desired namespace your specified.
|
||||
|
||||
@@ -314,13 +340,14 @@ kubectl get secrets -n <namespace of managed secret>
|
||||
</Info>
|
||||
|
||||
### Using managed secret in your deployment
|
||||
|
||||
Incorporating the managed secret created by the operator into your deployment can be achieved through several methods.
|
||||
Here, we will highlight three of the most common ways to utilize it. Learn more about Kubernetes secrets [here](https://kubernetes.io/docs/concepts/configuration/secret/)
|
||||
|
||||
<Accordion title="envFrom">
|
||||
This will take all the secrets from your managed secret and expose them to your container
|
||||
|
||||
```yaml
|
||||
````yaml
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: managed-secret # managed secret name
|
||||
@@ -352,9 +379,9 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
|
||||
name: managed-secret # <- name of managed secret
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
</Accordion>
|
||||
````
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="env">
|
||||
This will allow you to select individual secrets by key name from your managed secret and expose them to your container
|
||||
@@ -369,6 +396,7 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
|
||||
```
|
||||
|
||||
Example usage in a deployment
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -386,18 +414,17 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
containers: - name: nginx
|
||||
image: nginx:1.14.2
|
||||
env:
|
||||
- name: STRIPE_API_SECRET
|
||||
env: - name: STRIPE_API_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: managed-secret # <- name of managed secret
|
||||
key: STRIPE_API_SECRET
|
||||
ports:
|
||||
- containerPort: 80
|
||||
ports: - containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="volumes">
|
||||
@@ -407,9 +434,10 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
|
||||
- name: secrets-volume-name # The name of the volume under which secrets will be stored
|
||||
secret:
|
||||
secretName: managed-secret # managed secret name
|
||||
```
|
||||
````
|
||||
|
||||
You can then mount this volume to the container's filesystem so that your deployment can access the files containing the managed secrets
|
||||
|
||||
```yaml
|
||||
volumeMounts:
|
||||
- name: secrets-volume-name
|
||||
@@ -418,6 +446,7 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
|
||||
```
|
||||
|
||||
Example usage in a deployment
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -449,14 +478,18 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
|
||||
secret:
|
||||
secretName: managed-secret # <- managed secrets
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
## Auto redeployment
|
||||
|
||||
Deployments using managed secrets don't reload automatically on updates, so they may use outdated secrets unless manually redeployed.
|
||||
To address this, we added functionality to automatically redeploy your deployment when its managed secret updates.
|
||||
|
||||
### Enabling auto redeploy
|
||||
|
||||
To enable auto redeployment you simply have to add the following annotation to the deployment that consumes a managed secret
|
||||
|
||||
```yaml
|
||||
secrets.infisical.com/auto-reload: "true"
|
||||
```
|
||||
@@ -493,16 +526,18 @@ spec:
|
||||
</Accordion>
|
||||
|
||||
## Global configuration
|
||||
|
||||
To configure global settings that will apply to all instances of `InfisicalSecret`, you can define these configurations in a Kubernetes ConfigMap.
|
||||
For example, you can configure all `InfisicalSecret` instances to fetch secrets from a single backend API without specifying the `hostAPI` parameter for each instance.
|
||||
|
||||
### Available global properties
|
||||
| Property | Description | Default value
|
||||
| -------- | ------------------------------------- |------------------------
|
||||
| hostAPI | If `hostAPI` in `InfisicalSecret` instance is left empty, this value will be used | https://app.infisical.com/api
|
||||
|
||||
| Property | Description | Default value |
|
||||
| -------- | --------------------------------------------------------------------------------- | ----------------------------- |
|
||||
| hostAPI | If `hostAPI` in `InfisicalSecret` instance is left empty, this value will be used | https://app.infisical.com/api |
|
||||
|
||||
### Applying global configurations
|
||||
|
||||
All global configurations must reside in a Kubernetes ConfigMap named `infisical-config` in the namespace `infisical-operator-system`.
|
||||
To apply global configuration to the operator, copy the following yaml into `infisical-config.yaml` file.
|
||||
|
||||
@@ -527,7 +562,6 @@ Then apply this change via kubectl by running the following
|
||||
kubectl apply -f infisical-config.yaml
|
||||
```
|
||||
|
||||
|
||||
## Troubleshoot operator
|
||||
|
||||
If the operator is unable to fetch secrets from the API, it will not affect the managed Kubernetes secret.
|
||||
@@ -576,7 +610,6 @@ The managed secret created by the operator will not be deleted when the operator
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Useful Articles
|
||||
|
||||
- [Managing secrets in OpenShift with Infisical](https://xphyr.net/post/infisical_ocp/)
|
||||
|
@@ -32,6 +32,6 @@ This section covers the internals of Infisical including its technical underpinn
|
||||
icon="ticket"
|
||||
color="#000000"
|
||||
>
|
||||
Learn best practices for utilizing Infisical service tokens.
|
||||
Learn best practices for utilizing Infisical service tokens. Please note that service tokens are now deprecated and will be removed entirely in the future.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
@@ -2,6 +2,13 @@
|
||||
title: "Service tokens"
|
||||
description: "Understanding service tokens and their best practices."
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
||||
They will be removed in the future in accordance with the deprecation notice and timeline stated [here](https://infisical.com/blog/deprecating-api-keys).
|
||||
|
||||
</Warning>
|
||||
|
||||
Many clients use service tokens to authenticate and read/write secrets from/to Infisical; they can be created in your project settings.
|
||||
|
||||
@@ -28,6 +35,7 @@ Consider the token `st.abc.def.ghi`. Here, `st.abc.def` can be used to authentic
|
||||
|
||||
Note that when using service tokens via select client methods like SDK or CLI, cryptographic operations are abstracted for you that is the token is parsed and encryption/decryption operations are handled. If using service tokens with the REST API and end-to-end encryption enabled, then you will have to handle the encryption/decryption operations yourself.
|
||||
|
||||
|
||||
## Recommendations
|
||||
|
||||
### Issuance
|
||||
|
@@ -32,10 +32,7 @@
|
||||
"thumbsRating": true
|
||||
},
|
||||
"api": {
|
||||
"baseUrl": [
|
||||
"https://app.infisical.com",
|
||||
"http://localhost:8080"
|
||||
]
|
||||
"baseUrl": ["https://app.infisical.com", "http://localhost:8080"]
|
||||
},
|
||||
"topbarLinks": [
|
||||
{
|
||||
@@ -76,11 +73,7 @@
|
||||
"documentation/getting-started/introduction",
|
||||
{
|
||||
"group": "Quickstart",
|
||||
"pages": [
|
||||
"documentation/guides/local-development",
|
||||
"documentation/guides/staging",
|
||||
"documentation/guides/production"
|
||||
]
|
||||
"pages": ["documentation/guides/local-development"]
|
||||
},
|
||||
{
|
||||
"group": "Guides",
|
||||
@@ -146,10 +139,12 @@
|
||||
"documentation/platform/dynamic-secrets/postgresql",
|
||||
"documentation/platform/dynamic-secrets/mysql",
|
||||
"documentation/platform/dynamic-secrets/oracle",
|
||||
"documentation/platform/dynamic-secrets/cassandra"
|
||||
"documentation/platform/dynamic-secrets/cassandra",
|
||||
"documentation/platform/dynamic-secrets/aws-iam"
|
||||
]
|
||||
},
|
||||
"documentation/platform/groups"
|
||||
"documentation/platform/groups",
|
||||
"documentation/platform/audit-log-streams"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -196,16 +191,17 @@
|
||||
"group": "Self-host Infisical",
|
||||
"pages": [
|
||||
"self-hosting/overview",
|
||||
"self-hosting/configuration/requirements",
|
||||
{
|
||||
"group": "Installation methods",
|
||||
"pages": [
|
||||
"self-hosting/deployment-options/standalone-infisical",
|
||||
"self-hosting/deployment-options/docker-swarm",
|
||||
"self-hosting/deployment-options/docker-compose",
|
||||
"self-hosting/deployment-options/kubernetes-helm"
|
||||
]
|
||||
},
|
||||
"self-hosting/configuration/envars",
|
||||
"self-hosting/configuration/requirements",
|
||||
{
|
||||
"group": "Guides",
|
||||
"pages": [
|
||||
@@ -216,8 +212,7 @@
|
||||
{
|
||||
"group": "Reference architectures",
|
||||
"pages": [
|
||||
"self-hosting/reference-architectures/aws-ecs",
|
||||
"self-hosting/reference-architectures/on-premise"
|
||||
"self-hosting/reference-architectures/aws-ecs"
|
||||
]
|
||||
},
|
||||
"self-hosting/ee",
|
||||
@@ -374,15 +369,11 @@
|
||||
},
|
||||
{
|
||||
"group": "Build Tool Integrations",
|
||||
"pages": [
|
||||
"integrations/build-tools/gradle"
|
||||
]
|
||||
"pages": ["integrations/build-tools/gradle"]
|
||||
},
|
||||
{
|
||||
"group": "",
|
||||
"pages": [
|
||||
"sdks/overview"
|
||||
]
|
||||
"pages": ["sdks/overview"]
|
||||
},
|
||||
{
|
||||
"group": "SDK's",
|
||||
@@ -400,9 +391,7 @@
|
||||
"api-reference/overview/authentication",
|
||||
{
|
||||
"group": "Examples",
|
||||
"pages": [
|
||||
"api-reference/overview/examples/integration"
|
||||
]
|
||||
"pages": ["api-reference/overview/examples/integration"]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -491,6 +480,9 @@
|
||||
"api-reference/endpoints/secrets/read",
|
||||
"api-reference/endpoints/secrets/update",
|
||||
"api-reference/endpoints/secrets/delete",
|
||||
"api-reference/endpoints/secrets/create-many",
|
||||
"api-reference/endpoints/secrets/update-many",
|
||||
"api-reference/endpoints/secrets/delete-many",
|
||||
"api-reference/endpoints/secrets/attach-tags",
|
||||
"api-reference/endpoints/secrets/detach-tags"
|
||||
]
|
||||
@@ -531,15 +523,11 @@
|
||||
},
|
||||
{
|
||||
"group": "Service Tokens",
|
||||
"pages": [
|
||||
"api-reference/endpoints/service-tokens/get"
|
||||
]
|
||||
"pages": ["api-reference/endpoints/service-tokens/get"]
|
||||
},
|
||||
{
|
||||
"group": "Audit Logs",
|
||||
"pages": [
|
||||
"api-reference/endpoints/audit-logs/export-audit-log"
|
||||
]
|
||||
"pages": ["api-reference/endpoints/audit-logs/export-audit-log"]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -555,9 +543,7 @@
|
||||
},
|
||||
{
|
||||
"group": "",
|
||||
"pages": [
|
||||
"changelog/overview"
|
||||
]
|
||||
"pages": ["changelog/overview"]
|
||||
},
|
||||
{
|
||||
"group": "Contributing",
|
||||
@@ -581,9 +567,7 @@
|
||||
},
|
||||
{
|
||||
"group": "Contributing to SDK",
|
||||
"pages": [
|
||||
"contributing/sdk/developing"
|
||||
]
|
||||
"pages": ["contributing/sdk/developing"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "Requirements"
|
||||
title: "Hardware requirements"
|
||||
description: "Find out the minimal requirements for operating Infisical."
|
||||
---
|
||||
|
||||
|
@@ -12,7 +12,7 @@ to run a functional instance of Infisical.
|
||||
<Warning>
|
||||
This Docker Compose configuration is not designed for high-availability production scenarios.
|
||||
It includes just the essential components needed to set up an Infisical proof of concept (POC).
|
||||
Additional configuration is required to enhance data redundancy and ensure higher availability for production environments.
|
||||
To run Infisical in a highly available manner, give the [Docker Swarm guide](/self-hosting/deployment-options/docker-swarm).
|
||||
</Warning>
|
||||
|
||||
## Verify prerequisites
|
||||
|
216
docs/self-hosting/deployment-options/docker-swarm.mdx
Normal file
@@ -0,0 +1,216 @@
|
||||
---
|
||||
title: "Docker Swarm"
|
||||
description: "How to self Infisical with Docker Swarm (HA)."
|
||||
---
|
||||
|
||||
# Self-Hosting Infisical with Docker Swarm
|
||||
|
||||
This guide will provide step-by-step instructions on how to self-host Infisical using Docker Swarm. This is particularly helpful for those wanting to self host Infisical on premise while still maintaining high availability (HA) for the core Infisical components.
|
||||
The guide will demonstrate a setup with three nodes, ensuring that the cluster can tolerate the failure of one node while remaining fully operational.
|
||||
|
||||
## Docker Swarm
|
||||
|
||||
[Docker Swarm](https://docs.docker.com/engine/swarm/) is a native clustering and orchestration solution for Docker containers.
|
||||
It simplifies the deployment and management of containerized applications across multiple nodes, making it a great choice for self-hosting Infisical.
|
||||
|
||||
Unlike Kubernetes, which requires a deep understanding of the Kubernetes ecosystem, if you're accustomed to Docker and Docker Compose, you're already familiar with most of Docker Swarm.
|
||||
For this reason, we suggest teams use Docker Swarm to deploy Infisical in a highly available and fault tolerant manner.
|
||||
|
||||
## Prerequisites
|
||||
- Understanding of Docker Swarm
|
||||
- Bare/Virtual Machines with Docker installed on each VM.
|
||||
- Docker Swarm initialized on the VMs.
|
||||
|
||||
## Core Components for High Availability
|
||||
|
||||
The provided Docker stack includes the following core components to achieve high availability:
|
||||
|
||||
1. **Spilo**: [Spilo](https://github.com/zalando/spilo) is used to run PostgreSQL with [Patroni](https://github.com/zalando/patroni) for HA and automatic failover. It utilizes etcd for leader election of the PostgreSQL instances.
|
||||
|
||||
2. **Redis**: Redis is used for caching and is set up with Redis Sentinel for HA.
|
||||
The stack includes three Redis replicas and three Redis Sentinel instances for monitoring and failover.
|
||||
|
||||
3. **Infisical**: Infisical is stateless, allowing for easy scaling and replication across multiple nodes.
|
||||
|
||||
4. **HAProxy**: HAProxy is used as a load balancer to distribute traffic to the PostgreSQL and Redis instances.
|
||||
It is configured to perform health checks and route requests to the appropriate backend services.
|
||||
|
||||
## Node Failure Tolerance
|
||||
|
||||
To ensure Infisical is highly available and fault tolerant, it's important to choose the number of nodes in the cluster.
|
||||
The following table shows the relationship between the number of nodes and the maximum number of nodes that can be down while the cluster continues to function:
|
||||
|
||||
| Total Nodes | Max Nodes Down | Min Nodes Required |
|
||||
|-------------|----------------|-------------------|
|
||||
| 1 | 0 | 1 |
|
||||
| 2 | 0 | 2 |
|
||||
| 3 | 1 | 2 |
|
||||
| 4 | 1 | 3 |
|
||||
| 5 | 2 | 3 |
|
||||
| 6 | 2 | 4 |
|
||||
| 7 | 3 | 4 |
|
||||
|
||||
The formula for calculating the minimum number of nodes required is: `floor(n/2) + 1`, where `n` is the total number of nodes.
|
||||
|
||||
This guide will demonstrate a setup with three nodes, which allows for one node to be down while the cluster remains operational. This fault tolerance applies to the following components:
|
||||
|
||||
- Redis Sentinel: With three Sentinel instances, one instance can be down, and the remaining two can still form a quorum to make decisions.
|
||||
- Redis: With three Redis instances (one master and two replicas), one instance can be down, and the remaining two can continue to provide caching services.
|
||||
- PostgreSQL: With three PostgreSQL instances managed by Patroni and etcd, one instance can be down, and the remaining two can maintain data consistency and availability.
|
||||
- Manager Nodes: In a Docker Swarm cluster with three manager nodes, one manager node can be down, and the remaining two can continue to manage the cluster.
|
||||
For the sake of simplicity, the example in this guide only contains one manager node.
|
||||
|
||||
It's important to note that while the cluster can tolerate the failure of one node in a three-node setup, it's recommended to have a minimum of three nodes to ensure high availability.
|
||||
With two nodes, the failure of a single node can result in a loss of quorum and potential downtime.
|
||||
|
||||
## Docker Deployment Stack Overview
|
||||
|
||||
The [Docker stack file](https://github.com/Infisical/infisical/tree/main/docker-swarm) used in this guide defines the services and their configurations for deploying Infisical in a highly available manner. The main components of this stack are as follows.
|
||||
|
||||
1. **HAProxy**: The HAProxy service is configured to expose ports for accessing PostgreSQL (5433 for the master, 5434 for replicas), Redis master (6379), and the Infisical backend (8080). It uses a config file (`haproxy.cfg`) to define the load balancing and health check rules.
|
||||
|
||||
2. **Infisical**: The Infisical backend service is deployed with the latest PostgreSQL-compatible image. It is connected to the `infisical` network and uses secrets for environment variables.
|
||||
|
||||
3. **etcd**: Three etcd instances (etcd1, etcd2, etcd3) are deployed, one on each node, to provide distributed key-value storage for leader election and configuration management.
|
||||
|
||||
4. **Spilo**: Three Spilo instances (spolo1, spolo2, spolo3) are deployed, one on each node, to run PostgreSQL with Patroni for high availability. They are connected to the `infisical` network and use persistent volumes for data storage.
|
||||
|
||||
5. **Redis**: Three Redis instances (redis_replica0, redis_replica1, redis_replica2) are deployed, one on each node, with redis_replica0 acting as the master. They are connected to the `infisical` network.
|
||||
|
||||
6. **Redis Sentinel**: Three Redis Sentinel instances (redis_sentinel1, redis_sentinel2, redis_sentinel3) are deployed, one on each node, to monitor and manage the Redis instances. They are connected to the `infisical` network.
|
||||
|
||||
## Deployment instructions
|
||||
|
||||
<Steps>
|
||||
<Step title="Initialize Docker Swarm on one of the VMs by running the following command">
|
||||
```
|
||||
docker swarm init
|
||||
```
|
||||
|
||||
Replace `<MANAGER_NODE_IP>` with the IP address of the VM that will serve as the manager node. Remember to copy the join token returned by the this init command.
|
||||
|
||||
<Tip>
|
||||
For the sake of simplicity, we only use one manager node in this example deployment. However, in production settings, we recommended you have at least 3 manager nodes.
|
||||
</Tip>
|
||||
</Step>
|
||||
|
||||
<Step title="On the other VMs, join the Docker Swarm by running the command provided by the manager node">
|
||||
```
|
||||
docker swarm join --token <JOIN_TOKEN> <MANAGER_NODE_IP>:2377
|
||||
```
|
||||
|
||||
Replace `<JOIN_TOKEN>` with the token provided by the manager node during initialization.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Label the nodes with `node.labels.name` to specify their roles.">
|
||||
Labels on nodes will help us select where stateful components such as Postgres and Redis are deployed on. To label nodes, follow the steps below.
|
||||
|
||||
```
|
||||
docker node update --label-add name=node1 <NODE1_ID>
|
||||
docker node update --label-add name=node2 <NODE2_ID>
|
||||
docker node update --label-add name=node3 <NODE3_ID>
|
||||
```
|
||||
|
||||
Replace `<NODE1_ID>`, `<NODE2_ID>`, and `<NODE3_ID>` with the respective node IDs.
|
||||
To view the list of nodes and their ids, run the following on the manager node `docker node ls`.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Copy deployment assets to manager node">
|
||||
Copy the Docker stack YAML file, HAProxy configuration file and example `.env` file to the manager node. Ensure that all 3 files are placed in the same file directory.
|
||||
- [Docker stack file](https://github.com/Infisical/infisical/blob/main/docker-swarm/stack.yaml) (rename to infisical-stack.yaml)
|
||||
- [HA configuration file](https://github.com/Infisical/infisical/blob/main/docker-swarm/haproxy.cfg) (rename to haproxy.cfg)
|
||||
- [Example .env file](https://github.com/Infisical/infisical/blob/main/docker-swarm/.env-example) (rename to .env)
|
||||
</Step>
|
||||
|
||||
<Step title="Deploy stack">
|
||||
|
||||
```
|
||||
docker stack deploy -c infisical-stack.yaml infisical
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Check service status">
|
||||
```plain
|
||||
$ docker service ls
|
||||
ID NAME MODE REPLICAS IMAGE PORTS
|
||||
4kzq3ub8qgn9 infisical_etcd1 replicated 1/1 ghcr.io/zalando/spilo-16:3.2-p2
|
||||
tqx9t82bn8d9 infisical_etcd2 replicated 1/1 ghcr.io/zalando/spilo-16:3.2-p2
|
||||
t8vbkrasy8fz infisical_etcd3 replicated 1/1 ghcr.io/zalando/spilo-16:3.2-p2
|
||||
77iei42fcf6q infisical_haproxy global 4/4 haproxy:latest *:5002-5003->5433-5434/tcp, *:6379->6379/tcp, *:7001->7000/tcp, *:8080->8080/tcp
|
||||
jaewzqy8md56 infisical_infisical replicated 5/5 infisical/infisical:v0.60.1-postgres
|
||||
58w4zablfbtb infisical_redis_replica0 replicated 1/1 bitnami/redis:6.2.10
|
||||
w4yag2whq0un infisical_redis_replica1 replicated 1/1 bitnami/redis:6.2.10
|
||||
w03mriy0jave infisical_redis_replica2 replicated 1/1 bitnami/redis:6.2.10
|
||||
ppo6rk47hc9t infisical_redis_sentinel1 replicated 1/1 bitnami/redis-sentinel:6.2.10
|
||||
ub29vd0lnq7f infisical_redis_sentinel2 replicated 1/1 bitnami/redis-sentinel:6.2.10
|
||||
szg3yky7yji2 infisical_redis_sentinel3 replicated 1/1 bitnami/redis-sentinel:6.2.10
|
||||
eqtocpf5tiy0 infisical_spolo1 replicated 1/1 ghcr.io/zalando/spilo-16:3.2-p2
|
||||
3lznscvk7k5t infisical_spolo2 replicated 1/1 ghcr.io/zalando/spilo-16:3.2-p2
|
||||
v04ml7rz2j5q infisical_spolo3 replicated 1/1 ghcr.io/zalando/spilo-16:3.2-p2
|
||||
```
|
||||
|
||||
<Note>
|
||||
You'll notice that service `infisical_infisical` will not be in running state.
|
||||
This is expected as the database does not yet have the desired schemas.
|
||||
Once the database schema migrations have been successfully applied, this issue should be resolved.
|
||||
</Note>
|
||||
</Step>
|
||||
|
||||
<Step title="Run schema migrations">
|
||||
Run the schema migration to initialize the database. Follow the [guide here](/self-hosting/configuration/schema-migrations) to learn how.
|
||||
|
||||
To connect to the Postgres database, use the following default credentials defined in the Docker swarm: username: `postgres`, password: `postgres` and database: `postgres`.
|
||||
</Step>
|
||||
|
||||
<Step title="View service status">
|
||||

|
||||
To view the health of services in your Infisical cluster, visit port `<NODE-IP>:7001` of any node in your Docker swarm.
|
||||
This port will expose the HA Proxy stats.
|
||||
|
||||
Run the following command to view the IPs of the nodes in your docker swarm.
|
||||
|
||||
```plain
|
||||
$ docker node ls
|
||||
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
|
||||
0jnegl4gpo235l66nglcwc07t localhost Ready Active 26.0.2
|
||||
no1a7zwj88057k73m196ulkq6 * localhost Ready Active Leader 26.0.2
|
||||
wcb2x27w3tq7ht4v1h7ke49qk localhost Ready Active 26.0.2
|
||||
zov5q7uop7wpxc2ndz712v9oa localhost Ready Active 26.0.2
|
||||
```
|
||||
|
||||
<Info>
|
||||
The stats page may take 1-2 minutes to become accessible.
|
||||
</Info>
|
||||
</Step>
|
||||
|
||||
<Step title="Initialize Infisical">
|
||||

|
||||
Once all expected services are up and running, visit `<NODE-IP>:8080` of any node in the swarm. This will take you to the Infisical configuration page.
|
||||
</Step>
|
||||
|
||||
</Steps>
|
||||
|
||||
## FAQ
|
||||
<Accordion title="How do I scale Infisical cluster further?" defaultOpen="true">
|
||||
To further scale and make the system more resilient, you can add more nodes to the Docker Swarm and update the stack configuration accordingly:
|
||||
|
||||
1. Add new VMs and join them to the Docker Swarm as worker nodes.
|
||||
|
||||
2. Update the Docker stack YAML file to include the new nodes in the `deploy` section of the relevant services, specifying the appropriate `node.labels.name` constraints.
|
||||
|
||||
3. Update the HAProxy configuration file (`haproxy.cfg`) to include the new nodes in the backend sections for PostgreSQL and Redis.
|
||||
|
||||
4. Redeploy the updated stack using the `docker stack deploy` command.
|
||||
|
||||
Note that the database containers (PostgreSQL) are stateful and cannot be simply replicated. Instead, one database instance is deployed per node to ensure data consistency and avoid conflicts.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="How do I configure backups for Postgres and Redis?">
|
||||
Native tooling for scheduled backups of Postgres and Redis is currently in development.
|
||||
In the meantime, we recommend using a variety of open-source tools available for this purpose.
|
||||
For Postgres, [Spilo](https://github.com/zalando/spilo) provides built-in support for scheduled data dumps.
|
||||
You can explore other third party tools for managing db backups, one such tool is [docker-db-backup](https://github.com/tiredofit/docker-db-backup).
|
||||
</Accordion>
|
@@ -1,70 +0,0 @@
|
||||
---
|
||||
title: "On-premise"
|
||||
description: "Reference architecture for self-hosting Infisical on premise"
|
||||
---
|
||||
|
||||
Deploying Infisical on-premise with high availability requires deep knowledge in areas like networking, container orchestration, and database management.
|
||||
This guide presents a reference architecture that outlines how to achieve such a deployment effectively.
|
||||
For organizations that do not have the necessary resources or expertise, we recommend opting for managed, dedicated Infisical instances or engaging professional services to mitigate the complexities.
|
||||
|
||||
## System Overview
|
||||

|
||||
|
||||
The architecture above utilizes a combination of Kubernetes for orchestrating stateless components and virtual machines (VMs) or bare metal for stateful components.
|
||||
The infrastructure spans multiple data centers for redundancy and load distribution, enhancing availability and disaster recovery capabilities.
|
||||
You may duplicate the architecture in multiple data centers and join them via Consul to increase availability. This way, if one data center is out of order, active data centers will take over workloads.
|
||||
|
||||
### Stateful vs stateless workloads
|
||||
|
||||
To reduce the challenges of managing state within Kubernetes, including storage provisioning, persistent volume management, and intricate data backup and recovery processes, we strongly recommend deploying stateful components on Virtual Machines (VMs) or bare metal.
|
||||
As depicted in the architecture, Infisical is intentionally deployed on Kubernetes to leverage its strengths in managing stateless applications.
|
||||
Being stateless, Infisical fully benefits from Kubernetes' features like horizontal scaling, self-healing, and rolling updates and rollbacks.
|
||||
|
||||
## Core Components
|
||||
|
||||
### Kubernetes Cluster
|
||||
Infisical is deployed on a Kubernetes cluster, which allows for container management, auto-scaling, and self-healing capabilities.
|
||||
A load balancer sits in front of the Kubernetes cluster, directing traffic and ensuring even load distribution across the application nodes.
|
||||
This is the entry point where all other services will interact with Infisical.
|
||||
|
||||
|
||||
### Consul as the Networking Backbone
|
||||
Consul is an critical component in the reference architecture, serving as a unified service networking layer that links and controls services across different environments and data centers.
|
||||
It functions as the common communication channel between data centers for stateless applications on Kubernetes and stateful services such as databases on dedicated VMs or bare metal.
|
||||
|
||||
|
||||
### Postgres with Patroni
|
||||
The database layer is powered by Postgres, with [Patroni](https://patroni.readthedocs.io/en/latest/) providing automated management to create a high availability setup. Patroni leverages Consul for several critical operations:
|
||||
|
||||
- **Redundancy:** By managing a cluster of one primary and multiple secondary Postgres nodes, the architecture ensures redundancy.
|
||||
The primary node handles all the write operations, and secondary nodes handle read operations and are prepared to step up in case of primary failure.
|
||||
|
||||
- **Failover and Service Discovery:** Consul is integrated with Patroni for service discovery and health checks.
|
||||
When Patroni detects that the primary node is unhealthy, it uses Consul to elect a new primary node from the secondaries, thereby ensuring that the database service remains available.
|
||||
|
||||
- **Data Center Awareness:** Patroni configured with Consul is aware of the multi-data center setup and can handle failover across data centers if necessary, which further enhances the system's availability.
|
||||
|
||||
### Redis with Redis Sentinel
|
||||
For caching and message brokering:
|
||||
|
||||
- Redis is deployed with a primary-replica setup.
|
||||
- Redis Sentinel monitors the Redis nodes, providing automatic failover and service discovery.
|
||||
- Write operations go to the primary node, and replicas serve read operations, ensuring data integrity and availability.
|
||||
|
||||
## Multi data center deployment
|
||||
Infisical can be deployed across a number of data centers to both increase performance and resiliency to disaster scenarios.
|
||||
For mission critical deployment of Infisical, we recommend deploying Infisical on at least 3 data centers to reduce downtime in the event of complete data center malfunction.
|
||||
|
||||
### Data Center A
|
||||
Data Center A houses the primary nodes of both Postgres and Redis, which handle all write operations. The secondary nodes and replicas serve as hot standbys for failover. Consul servers maintain the state of the cluster, elect a leader, and facilitate service discovery.
|
||||
|
||||
### $n^{th}$ data center
|
||||
The $n^{th}$ data center acts as a performance and disaster recovery site, featuring a mesh gateway that enables cross-data center service discovery and configuration. It houses additional secondary nodes for Postgres and Redis replicas, which are ready to be promoted in case the primary data center fails. Additionally, this data center can reduce the latency of applications that need to interact with Infisical, particularly if those applications or services are geographically closer to this data center.
|
||||
|
||||
## Considerations
|
||||
|
||||
The complexity of an on-premise deployment scales with the level of availability required. This reference architecture provides a robust framework for organizations aiming for high availability and disaster resilience. However, it's important to recognize that this is not a one-size-fits-all solution.
|
||||
|
||||
Organizations with less stringent Recovery Time Objectives (RTO) might find that [simpler deployments methods](/self-hosting/deployment-options/docker-compose) using tools such as Docker Compose are adequate. Such setups can still provide a reasonable level of service continuity without the complexities involved in managing a multi-data center environment with Kubernetes, Consul, and other high-availability components.
|
||||
|
||||
Ultimately, the choice of architecture should be guided by a thorough analysis of business needs, available resources, and expertise.
|
BIN
frontend/public/images/integrations/Agent.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
frontend/public/images/integrations/Ansible.png
Normal file
After Width: | Height: | Size: 9.0 KiB |