Compare commits
112 Commits
patch-5
...
docs/ansib
Author | SHA1 | Date | |
---|---|---|---|
6a001a214b | |||
9fe2021d9f | |||
9e2bd31833 | |||
e88b0ad3c4 | |||
74644fd8bb | |||
2069ac1554 | |||
5a2516e0a7 | |||
b52bc3bed7 | |||
4a153e5658 | |||
7324822be5 | |||
766f301aea | |||
b815e3eb56 | |||
31231cfcca | |||
ee772e4a77 | |||
7bc29c5981 | |||
e9a89930da | |||
b85499859c | |||
7f17194c0f | |||
1e1ad450d2 | |||
5287b322d8 | |||
45d96be1ff | |||
12840bfdbd | |||
fef5369738 | |||
c94b7d63f6 | |||
485ddc5c50 | |||
edd9c66e49 | |||
0a3b85534b | |||
ec2cc5162e | |||
7ce472957c | |||
8529e0da3d | |||
e5a5433f10 | |||
ee6e518ff8 | |||
15a7222505 | |||
25d482cc62 | |||
785a2bec6a | |||
449466f326 | |||
4131e9c3f1 | |||
310595256f | |||
1737880e58 | |||
b72483f5f2 | |||
ee14bda706 | |||
e56463d52b | |||
ebd3d7c7c4 | |||
9ecbfe201b | |||
ba2a03897f | |||
304f14c0ed | |||
51e5c25e16 | |||
0f6490b1e7 | |||
f894e48fcb | |||
37cfa22619 | |||
94557344b7 | |||
d5063018eb | |||
51d68505d3 | |||
ade27ad072 | |||
683c512bce | |||
43ff28b5fb | |||
ce41855e84 | |||
d24461b17c | |||
1797e56f9f | |||
74f3ca5356 | |||
db27beaf0b | |||
d6e55f51f2 | |||
e9b5996567 | |||
094fe73917 | |||
dc3f85e92e | |||
c463256058 | |||
8df22302fd | |||
f37fa2bbf5 | |||
597c9d6f2a | |||
24d2eea930 | |||
382cb910af | |||
6725475575 | |||
026864951b | |||
287ed05ab7 | |||
37b036e614 | |||
024914c168 | |||
19e8b6d37b | |||
b6d648f1f3 | |||
a514a62a29 | |||
2f24956651 | |||
13d058025c | |||
8ccaa7f29b | |||
b83964051c | |||
0a2b078bdc | |||
40d16fa996 | |||
a3739cfe50 | |||
a73623258e | |||
6da39f41a6 | |||
69bbbfcfd8 | |||
c9d58ec77d | |||
cb364186d8 | |||
918afe05b6 | |||
e822820151 | |||
b5ac49eefe | |||
b21d1a0ed2 | |||
70f1122362 | |||
ea03db8a2c | |||
38d9abca17 | |||
5bed2580c3 | |||
d0b899897b | |||
1861dc85de | |||
bc6bf33674 | |||
44fd35baf5 | |||
8ddfee4c36 | |||
4d0bff4377 | |||
c7b2489d0b | |||
68eb0f8dd9 | |||
5941e8e836 | |||
80e50d13ec | |||
99c8dda4e1 | |||
14c8e3fa3b | |||
7aa3cb53a2 |
@ -108,7 +108,7 @@ brews:
|
||||
zsh_completion.install "completions/infisical.zsh" => "_infisical"
|
||||
fish_completion.install "completions/infisical.fish"
|
||||
man1.install "manpages/infisical.1.gz"
|
||||
- name: 'infisical@{{.Version}}'
|
||||
- name: "infisical@{{.Version}}"
|
||||
tap:
|
||||
owner: Infisical
|
||||
name: homebrew-get-cli
|
||||
@ -186,12 +186,14 @@ aurs:
|
||||
# man pages
|
||||
install -Dm644 "./manpages/infisical.1.gz" "${pkgdir}/usr/share/man/man1/infisical.1.gz"
|
||||
|
||||
# dockers:
|
||||
# - dockerfile: cli/docker/Dockerfile
|
||||
# goos: linux
|
||||
# goarch: amd64
|
||||
# ids:
|
||||
# - infisical
|
||||
# image_templates:
|
||||
# - "infisical/cli:{{ .Version }}"
|
||||
# - "infisical/cli:latest"
|
||||
dockers:
|
||||
- dockerfile: docker/alpine
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
ids:
|
||||
- all-other-builds
|
||||
image_templates:
|
||||
- "infisical/cli:{{ .Version }}"
|
||||
- "infisical/cli:{{ .Major }}.{{ .Minor }}"
|
||||
- "infisical/cli:{{ .Major }}"
|
||||
- "infisical/cli:latest"
|
||||
|
@ -129,7 +129,7 @@ Note that this security address should be used only for undisclosed vulnerabilit
|
||||
|
||||
## Contributing
|
||||
|
||||
Whether it's big or small, we love contributions. Check out our guide to see how to [get started](https://infisical.com/docs/contributing/overview).
|
||||
Whether it's big or small, we love contributions. Check out our guide to see how to [get started](https://infisical.com/docs/contributing/getting-started).
|
||||
|
||||
Not sure where to get started? You can:
|
||||
|
||||
|
30
backend/package-lock.json
generated
@ -60,7 +60,7 @@
|
||||
"pino": "^8.16.1",
|
||||
"pino-http": "^8.5.1",
|
||||
"posthog-node": "^2.6.0",
|
||||
"probot": "^12.3.1",
|
||||
"probot": "^12.3.3",
|
||||
"query-string": "^7.1.3",
|
||||
"rate-limit-mongo": "^2.3.2",
|
||||
"rimraf": "^3.0.2",
|
||||
@ -5991,9 +5991,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/webhooks": {
|
||||
"version": "9.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.26.0.tgz",
|
||||
"integrity": "sha512-foZlsgrTDwAmD5j2Czn6ji10lbWjGDVsUxTIydjG9KTkAWKJrFapXJgO5SbGxRwfPd3OJdhK3nA2YPqVhxLXqA==",
|
||||
"version": "9.26.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.26.3.tgz",
|
||||
"integrity": "sha512-DLGk+gzeVq5oK89Bo601txYmyrelMQ7Fi5EnjHE0Xs8CWicy2xkmnJMKptKJrBJpstqbd/9oeDFi/Zj2pudBDQ==",
|
||||
"dependencies": {
|
||||
"@octokit/request-error": "^2.0.2",
|
||||
"@octokit/webhooks-methods": "^2.0.0",
|
||||
@ -16306,9 +16306,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/probot": {
|
||||
"version": "12.3.1",
|
||||
"resolved": "https://registry.npmjs.org/probot/-/probot-12.3.1.tgz",
|
||||
"integrity": "sha512-ECSgycmAC0ILEK6cOa+x3QPufP5JybsuohOFCYr3glQU5SkbmypZJE/Sfio9mxAFHK5LCXveIDsfZCxf6ck4JA==",
|
||||
"version": "12.3.3",
|
||||
"resolved": "https://registry.npmjs.org/probot/-/probot-12.3.3.tgz",
|
||||
"integrity": "sha512-cdtKd+xISzi8sw6++BYBXleRknCA6hqUMoHj/sJqQBrjbNxQLhfeFCq9O2d0Z4eShsy5YFRR3MWwDKJ9uAE0CA==",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^3.2.4",
|
||||
"@octokit/plugin-enterprise-compatibility": "^1.2.8",
|
||||
@ -16317,7 +16317,7 @@
|
||||
"@octokit/plugin-retry": "^3.0.6",
|
||||
"@octokit/plugin-throttling": "^3.3.4",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"@octokit/webhooks": "^9.8.4",
|
||||
"@octokit/webhooks": "^9.26.3",
|
||||
"@probot/get-private-key": "^1.1.0",
|
||||
"@probot/octokit-plugin-config": "^1.0.0",
|
||||
"@probot/pino": "^2.2.0",
|
||||
@ -23392,9 +23392,9 @@
|
||||
}
|
||||
},
|
||||
"@octokit/webhooks": {
|
||||
"version": "9.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.26.0.tgz",
|
||||
"integrity": "sha512-foZlsgrTDwAmD5j2Czn6ji10lbWjGDVsUxTIydjG9KTkAWKJrFapXJgO5SbGxRwfPd3OJdhK3nA2YPqVhxLXqA==",
|
||||
"version": "9.26.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.26.3.tgz",
|
||||
"integrity": "sha512-DLGk+gzeVq5oK89Bo601txYmyrelMQ7Fi5EnjHE0Xs8CWicy2xkmnJMKptKJrBJpstqbd/9oeDFi/Zj2pudBDQ==",
|
||||
"requires": {
|
||||
"@octokit/request-error": "^2.0.2",
|
||||
"@octokit/webhooks-methods": "^2.0.0",
|
||||
@ -31039,9 +31039,9 @@
|
||||
}
|
||||
},
|
||||
"probot": {
|
||||
"version": "12.3.1",
|
||||
"resolved": "https://registry.npmjs.org/probot/-/probot-12.3.1.tgz",
|
||||
"integrity": "sha512-ECSgycmAC0ILEK6cOa+x3QPufP5JybsuohOFCYr3glQU5SkbmypZJE/Sfio9mxAFHK5LCXveIDsfZCxf6ck4JA==",
|
||||
"version": "12.3.3",
|
||||
"resolved": "https://registry.npmjs.org/probot/-/probot-12.3.3.tgz",
|
||||
"integrity": "sha512-cdtKd+xISzi8sw6++BYBXleRknCA6hqUMoHj/sJqQBrjbNxQLhfeFCq9O2d0Z4eShsy5YFRR3MWwDKJ9uAE0CA==",
|
||||
"requires": {
|
||||
"@octokit/core": "^3.2.4",
|
||||
"@octokit/plugin-enterprise-compatibility": "^1.2.8",
|
||||
@ -31050,7 +31050,7 @@
|
||||
"@octokit/plugin-retry": "^3.0.6",
|
||||
"@octokit/plugin-throttling": "^3.3.4",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"@octokit/webhooks": "^9.8.4",
|
||||
"@octokit/webhooks": "^9.26.3",
|
||||
"@probot/get-private-key": "^1.1.0",
|
||||
"@probot/octokit-plugin-config": "^1.0.0",
|
||||
"@probot/pino": "^2.2.0",
|
||||
|
@ -51,7 +51,7 @@
|
||||
"pino": "^8.16.1",
|
||||
"pino-http": "^8.5.1",
|
||||
"posthog-node": "^2.6.0",
|
||||
"probot": "^12.3.1",
|
||||
"probot": "^12.3.3",
|
||||
"query-string": "^7.1.3",
|
||||
"rate-limit-mongo": "^2.3.2",
|
||||
"rimraf": "^3.0.2",
|
||||
|
@ -4962,7 +4962,8 @@
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"apiKeyAuth": []
|
||||
"apiKeyAuth": [],
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { Request, Response } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import { standardRequest } from "../../config/request";
|
||||
import { getApps, getTeams, revokeAccess } from "../../integrations";
|
||||
import { Bot, IntegrationAuth, Workspace } from "../../models";
|
||||
import { Bot, IIntegrationAuth, Integration, IntegrationAuth, Workspace } from "../../models";
|
||||
import { EventType } from "../../ee/models";
|
||||
import { IntegrationService } from "../../services";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
@ -130,7 +130,6 @@ export const oAuthExchange = async (req: Request, res: Response) => {
|
||||
export const saveIntegrationToken = async (req: Request, res: Response) => {
|
||||
// TODO: refactor
|
||||
// TODO: check if access token is valid for each integration
|
||||
let integrationAuth;
|
||||
const {
|
||||
body: { workspaceId, integration, url, accessId, namespace, accessToken, refreshToken }
|
||||
} = await validateRequest(reqValidator.SaveIntegrationAccessTokenV1, req);
|
||||
@ -152,31 +151,21 @@ export const saveIntegrationToken = async (req: Request, res: Response) => {
|
||||
|
||||
if (!bot) throw new Error("Bot must be enabled to save integration access token");
|
||||
|
||||
integrationAuth = await IntegrationAuth.findOneAndUpdate(
|
||||
{
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
integration
|
||||
},
|
||||
{
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
integration,
|
||||
url,
|
||||
namespace,
|
||||
algorithm: ALGORITHM_AES_256_GCM,
|
||||
keyEncoding: ENCODING_SCHEME_UTF8,
|
||||
...(integration === INTEGRATION_GCP_SECRET_MANAGER
|
||||
? {
|
||||
metadata: {
|
||||
authMethod: "serviceAccount"
|
||||
}
|
||||
let integrationAuth = await new IntegrationAuth({
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
integration,
|
||||
url,
|
||||
namespace,
|
||||
algorithm: ALGORITHM_AES_256_GCM,
|
||||
keyEncoding: ENCODING_SCHEME_UTF8,
|
||||
...(integration === INTEGRATION_GCP_SECRET_MANAGER
|
||||
? {
|
||||
metadata: {
|
||||
authMethod: "serviceAccount"
|
||||
}
|
||||
: {})
|
||||
},
|
||||
{
|
||||
new: true,
|
||||
upsert: true
|
||||
}
|
||||
);
|
||||
}
|
||||
: {})
|
||||
}).save();
|
||||
|
||||
// encrypt and save integration access details
|
||||
if (refreshToken) {
|
||||
@ -188,12 +177,12 @@ export const saveIntegrationToken = async (req: Request, res: Response) => {
|
||||
|
||||
// encrypt and save integration access details
|
||||
if (accessId || accessToken) {
|
||||
integrationAuth = await IntegrationService.setIntegrationAuthAccess({
|
||||
integrationAuth = (await IntegrationService.setIntegrationAuthAccess({
|
||||
integrationAuthId: integrationAuth._id.toString(),
|
||||
accessId,
|
||||
accessToken,
|
||||
accessExpiresAt: undefined
|
||||
});
|
||||
})) as IIntegrationAuth;
|
||||
}
|
||||
|
||||
if (!integrationAuth) throw new Error("Failed to save integration access token");
|
||||
@ -1208,13 +1197,64 @@ export const getIntegrationAuthTeamCityBuildConfigs = async (req: Request, res:
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete all integration authorizations and integrations for workspace with id [workspaceId]
|
||||
* with integration name [integration]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const deleteIntegrationAuths = async (req: Request, res: Response) => {
|
||||
const {
|
||||
query: { integration, workspaceId }
|
||||
} = await validateRequest(reqValidator.DeleteIntegrationAuthsV1, req);
|
||||
|
||||
const { permission } = await getAuthDataProjectPermissions({
|
||||
authData: req.authData,
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Delete,
|
||||
ProjectPermissionSub.Integrations
|
||||
);
|
||||
|
||||
const integrationAuths = await IntegrationAuth.deleteMany({
|
||||
integration,
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
const integrations = await Integration.deleteMany({
|
||||
integration,
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UNAUTHORIZE_INTEGRATION,
|
||||
metadata: {
|
||||
integration
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
integrationAuths,
|
||||
integrations
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete integration authorization with id [integrationAuthId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const deleteIntegrationAuth = async (req: Request, res: Response) => {
|
||||
export const deleteIntegrationAuthById = async (req: Request, res: Response) => {
|
||||
const {
|
||||
params: { integrationAuthId }
|
||||
} = await validateRequest(reqValidator.DeleteIntegrationAuthV1, req);
|
||||
|
@ -251,6 +251,21 @@ export const deleteIntegration = async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
if (!deletedIntegration) throw new Error("Failed to find integration");
|
||||
|
||||
const numOtherIntegrationsUsingSameAuth = await Integration.countDocuments({
|
||||
integrationAuth: deletedIntegration.integrationAuth,
|
||||
_id: {
|
||||
$nin: [deletedIntegration._id]
|
||||
}
|
||||
});
|
||||
|
||||
if (numOtherIntegrationsUsingSameAuth === 0) {
|
||||
// no other integrations are using the same integration auth
|
||||
// -> delete integration auth associated with the integration being deleted
|
||||
await IntegrationAuth.deleteOne({
|
||||
_id: deletedIntegration.integrationAuth
|
||||
});
|
||||
}
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
|
@ -111,11 +111,17 @@ export const createSecretImp = async (req: Request, res: Response) => {
|
||||
authData: req.authData,
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
subject(ProjectPermissionSub.Secrets, { environment: secretImport.environment, secretPath: secretImport.secretPath })
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
const folders = await Folder.findOne({
|
||||
@ -323,7 +329,7 @@ export const updateSecretImport = async (req: Request, res: Response) => {
|
||||
authData: req.authData,
|
||||
workspaceId: importSecDoc.workspace
|
||||
});
|
||||
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
@ -331,6 +337,13 @@ export const updateSecretImport = async (req: Request, res: Response) => {
|
||||
secretPath
|
||||
})
|
||||
);
|
||||
|
||||
secretImports.forEach(({ environment, secretPath }) => {
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
const orderBefore = importSecDoc.imports;
|
||||
@ -453,7 +466,7 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
|
||||
authData: req.authData,
|
||||
workspaceId: importSecDoc.workspace
|
||||
});
|
||||
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Delete,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
@ -620,7 +633,7 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
|
||||
authData: req.authData,
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
@ -677,7 +690,7 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
|
||||
authData: req.authData,
|
||||
workspaceId: importSecDoc.workspace
|
||||
});
|
||||
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
|
@ -129,9 +129,14 @@ export const renewAccessToken = async (req: Request, res: Response) => {
|
||||
accessTokenTTL,
|
||||
accessTokenLastRenewedAt,
|
||||
accessTokenMaxTTL,
|
||||
createdAt: accessTokenCreatedAt
|
||||
createdAt: accessTokenCreatedAt,
|
||||
accessTokenNumUses,
|
||||
accessTokenNumUsesLimit
|
||||
} = identityAccessToken;
|
||||
|
||||
if (accessTokenNumUses >= accessTokenNumUsesLimit) {
|
||||
throw BadRequestError({ message: "Unable to renew because access token number of uses limit reached" })
|
||||
}
|
||||
|
||||
// ttl check
|
||||
if (accessTokenTTL > 0) {
|
||||
@ -545,7 +550,7 @@ export const attachIdentityUniversalAuth = async (req: Request, res: Response) =
|
||||
|
||||
// validate trusted ips
|
||||
const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => {
|
||||
if (!plan.ipAllowlisting && clientSecretTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({
|
||||
if (!plan.ipAllowlisting && (clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && clientSecretTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
|
||||
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
||||
});
|
||||
|
||||
@ -559,7 +564,7 @@ export const attachIdentityUniversalAuth = async (req: Request, res: Response) =
|
||||
});
|
||||
|
||||
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => {
|
||||
if (!plan.ipAllowlisting && accessTokenTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({
|
||||
if (!plan.ipAllowlisting && (accessTokenTrustedIp.ipAddress !== "0.0.0.0/0" && accessTokenTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
|
||||
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
||||
});
|
||||
|
||||
@ -745,7 +750,7 @@ export const updateIdentityUniversalAuth = async (req: Request, res: Response) =
|
||||
let reformattedClientSecretTrustedIps;
|
||||
if (clientSecretTrustedIps) {
|
||||
reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => {
|
||||
if (!plan.ipAllowlisting && clientSecretTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({
|
||||
if (!plan.ipAllowlisting && (clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && clientSecretTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
|
||||
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
||||
});
|
||||
|
||||
@ -762,7 +767,7 @@ export const updateIdentityUniversalAuth = async (req: Request, res: Response) =
|
||||
let reformattedAccessTokenTrustedIps;
|
||||
if (accessTokenTrustedIps) {
|
||||
reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => {
|
||||
if (!plan.ipAllowlisting && accessTokenTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({
|
||||
if (!plan.ipAllowlisting && (accessTokenTrustedIp.ipAddress !== "0.0.0.0/0" && accessTokenTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
|
||||
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
||||
});
|
||||
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
IdentityMembershipOrg,
|
||||
Membership,
|
||||
IWorkspace,
|
||||
Identity,
|
||||
IdentityMembership,
|
||||
IdentityMembershipOrg,
|
||||
Membership,
|
||||
MembershipOrg,
|
||||
User,
|
||||
Workspace
|
||||
} from "../../models";
|
||||
import { Role } from "../../ee/models";
|
||||
@ -298,7 +302,8 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
||||
#swagger.description = 'Return projects in organization that user is part of'
|
||||
|
||||
#swagger.security = [{
|
||||
"apiKeyAuth": []
|
||||
"apiKeyAuth": [],
|
||||
"bearerAuth": []
|
||||
}]
|
||||
|
||||
#swagger.parameters['organizationId'] = {
|
||||
@ -326,6 +331,7 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
const {
|
||||
params: { organizationId }
|
||||
} = await validateRequest(reqValidator.GetOrgWorkspacesv2, req);
|
||||
@ -351,13 +357,27 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
||||
).map((w) => w._id.toString())
|
||||
);
|
||||
|
||||
const workspaces = (
|
||||
await Membership.find({
|
||||
user: req.user._id
|
||||
}).populate("workspace")
|
||||
)
|
||||
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
||||
.map((m) => m.workspace);
|
||||
let workspaces: IWorkspace[] = [];
|
||||
|
||||
if (req.authData.authPayload instanceof Identity) {
|
||||
workspaces = (
|
||||
await IdentityMembership.find({
|
||||
identity: req.authData.authPayload._id
|
||||
}).populate<{ workspace: IWorkspace }>("workspace")
|
||||
)
|
||||
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
||||
.map((m) => m.workspace);
|
||||
}
|
||||
|
||||
if (req.authData.authPayload instanceof User) {
|
||||
workspaces = (
|
||||
await Membership.find({
|
||||
user: req.authData.authPayload._id
|
||||
}).populate<{ workspace: IWorkspace }>("workspace")
|
||||
)
|
||||
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
||||
.map((m) => m.workspace);
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
workspaces
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
ProjectPermissionSub,
|
||||
getAuthDataProjectPermissions
|
||||
} from "../../ee/services/ProjectRoleService";
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import { ForbiddenError, subject } from "@casl/ability";
|
||||
import { Types } from "mongoose";
|
||||
|
||||
/**
|
||||
@ -86,6 +86,14 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
||||
ProjectPermissionSub.ServiceTokens
|
||||
);
|
||||
|
||||
scopes.forEach(({ environment, secretPath }) => {
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: secretPath })
|
||||
);
|
||||
})
|
||||
|
||||
|
||||
const secret = crypto.randomBytes(16).toString("hex");
|
||||
const secretHash = await bcrypt.hash(secret, await getSaltRounds());
|
||||
|
||||
|
@ -348,7 +348,7 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
}
|
||||
*/
|
||||
const {
|
||||
query: { secretPath, environment, workspaceId, type, include_imports },
|
||||
query: { secretPath, environment, workspaceId, type, include_imports, version },
|
||||
params: { secretName }
|
||||
} = await validateRequest(reqValidator.GetSecretByNameRawV3, req);
|
||||
|
||||
@ -371,7 +371,8 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
type,
|
||||
secretPath,
|
||||
authData: req.authData,
|
||||
include_imports
|
||||
include_imports,
|
||||
version
|
||||
});
|
||||
|
||||
const key = await BotService.getWorkspaceKeyWithBot({
|
||||
@ -865,7 +866,7 @@ export const getSecrets = async (req: Request, res: Response) => {
|
||||
*/
|
||||
export const getSecretByName = async (req: Request, res: Response) => {
|
||||
const {
|
||||
query: { secretPath, environment, workspaceId, type, include_imports },
|
||||
query: { secretPath, environment, workspaceId, type, include_imports, version },
|
||||
params: { secretName }
|
||||
} = await validateRequest(reqValidator.GetSecretByNameV3, req);
|
||||
|
||||
@ -888,7 +889,8 @@ export const getSecretByName = async (req: Request, res: Response) => {
|
||||
type,
|
||||
secretPath,
|
||||
authData: req.authData,
|
||||
include_imports
|
||||
include_imports,
|
||||
version
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
|
@ -17,12 +17,12 @@ export const getSecretApprovalRequestCount = async (req: Request, res: Response)
|
||||
} = await validateRequest(reqValidator.getSecretApprovalRequestCount, req);
|
||||
|
||||
if (!(req.authData.authPayload instanceof User)) return;
|
||||
|
||||
|
||||
const membership = await Membership.findOne({
|
||||
user: req.authData.authPayload._id,
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
|
||||
if (!membership) throw UnauthorizedRequestError();
|
||||
|
||||
const approvalRequestCount = await SecretApprovalRequest.aggregate([
|
||||
@ -73,12 +73,12 @@ export const getSecretApprovalRequests = async (req: Request, res: Response) =>
|
||||
} = await validateRequest(reqValidator.getSecretApprovalRequests, req);
|
||||
|
||||
if (!(req.authData.authPayload instanceof User)) return;
|
||||
|
||||
|
||||
const membership = await Membership.findOne({
|
||||
user: req.authData.authPayload._id,
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
|
||||
if (!membership) throw UnauthorizedRequestError();
|
||||
|
||||
const query = {
|
||||
@ -168,13 +168,13 @@ export const getSecretApprovalRequestDetails = async (req: Request, res: Respons
|
||||
user: req.authData.authPayload._id,
|
||||
workspace: secretApprovalRequest.workspace
|
||||
});
|
||||
|
||||
|
||||
if (!membership) throw UnauthorizedRequestError();
|
||||
|
||||
// allow to fetch only if its admin or is the committer or approver
|
||||
if (
|
||||
membership.role !== "admin" &&
|
||||
secretApprovalRequest.committer !== membership.id &&
|
||||
!secretApprovalRequest.committer.equals(membership.id) &&
|
||||
!secretApprovalRequest.policy.approvers.find(
|
||||
(approverId) => approverId.toString() === membership._id.toString()
|
||||
)
|
||||
@ -215,7 +215,7 @@ export const updateSecretApprovalReviewStatus = async (req: Request, res: Respon
|
||||
user: req.authData.authPayload._id,
|
||||
workspace: secretApprovalRequest.workspace
|
||||
});
|
||||
|
||||
|
||||
if (!membership) throw UnauthorizedRequestError();
|
||||
|
||||
if (
|
||||
@ -257,7 +257,7 @@ export const mergeSecretApprovalRequest = async (req: Request, res: Response) =>
|
||||
user: req.authData.authPayload._id,
|
||||
workspace: secretApprovalRequest.workspace
|
||||
});
|
||||
|
||||
|
||||
if (!membership) throw UnauthorizedRequestError();
|
||||
|
||||
if (
|
||||
@ -307,7 +307,7 @@ export const updateSecretApprovalRequestStatus = async (req: Request, res: Respo
|
||||
user: req.authData.authPayload._id,
|
||||
workspace: secretApprovalRequest.workspace
|
||||
});
|
||||
|
||||
|
||||
if (!membership) throw UnauthorizedRequestError();
|
||||
|
||||
if (
|
||||
|
@ -8,7 +8,10 @@ export enum UserAgentType {
|
||||
WEB = "web",
|
||||
CLI = "cli",
|
||||
K8_OPERATOR = "k8-operator",
|
||||
OTHER = "other"
|
||||
TERRAFORM = "terraform",
|
||||
OTHER = "other",
|
||||
PYTHON_SDK = "InfisicalPythonSDK",
|
||||
NODE_SDK = "InfisicalNodeSDK"
|
||||
}
|
||||
|
||||
export enum EventType {
|
||||
|
@ -10,7 +10,7 @@ export const apiLimiter = rateLimit({
|
||||
// errorHandler: console.error.bind(null, 'rate-limit-mongo')
|
||||
// }),
|
||||
windowMs: 60 * 1000,
|
||||
max: 350,
|
||||
max: 480,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
skip: (request) => {
|
||||
@ -30,7 +30,7 @@ const authLimit = rateLimit({
|
||||
// collectionName: "expressRateRecords-authLimit",
|
||||
// }),
|
||||
windowMs: 60 * 1000,
|
||||
max: 100,
|
||||
max: 300,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
keyGenerator: (req, res) => {
|
||||
@ -46,8 +46,8 @@ export const passwordLimiter = rateLimit({
|
||||
// errorHandler: console.error.bind(null, 'rate-limit-mongo'),
|
||||
// collectionName: "expressRateRecords-passwordLimiter",
|
||||
// }),
|
||||
windowMs: 60 * 60 * 1000,
|
||||
max: 10,
|
||||
windowMs: 60 * 1000,
|
||||
max: 300,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
keyGenerator: (req, res) => {
|
||||
|
@ -579,7 +579,9 @@ export const getSecretsHelper = async ({
|
||||
event: "secrets pulled",
|
||||
distinctId: await TelemetryService.getDistinctId({ authData }),
|
||||
properties: {
|
||||
numberOfSecrets: shouldRecordK8Event ? approximateForNoneCapturedEvents : secrets.length,
|
||||
numberOfSecrets: shouldRecordK8Event
|
||||
? approximateForNoneCapturedEvents
|
||||
: secrets.length,
|
||||
environment,
|
||||
workspaceId,
|
||||
folderId,
|
||||
@ -611,42 +613,86 @@ export const getSecretHelper = async ({
|
||||
type,
|
||||
authData,
|
||||
secretPath = "/",
|
||||
include_imports = true
|
||||
include_imports = true,
|
||||
version
|
||||
}: GetSecretParams) => {
|
||||
const secretBlindIndex = await generateSecretBlindIndexHelper({
|
||||
secretName,
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
let secret: ISecret | null | undefined = null;
|
||||
|
||||
// if using service token filter towards the folderId by secretpath
|
||||
|
||||
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
||||
|
||||
// try getting personal secret first (if exists)
|
||||
secret = await Secret.findOne({
|
||||
secretBlindIndex,
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
folder: folderId,
|
||||
type: type ?? SECRET_PERSONAL,
|
||||
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {})
|
||||
}).lean();
|
||||
|
||||
if (!secret) {
|
||||
// case: failed to find personal secret matching criteria
|
||||
// -> find shared secret matching criteria
|
||||
if (version === undefined) {
|
||||
secret = await Secret.findOne({
|
||||
secretBlindIndex,
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
folder: folderId,
|
||||
type: SECRET_SHARED
|
||||
type: type ?? SECRET_PERSONAL,
|
||||
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {})
|
||||
}).lean();
|
||||
} else {
|
||||
const secretVersion = await SecretVersion.findOne({
|
||||
secretBlindIndex,
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
folder: folderId,
|
||||
type: type ?? SECRET_PERSONAL,
|
||||
version
|
||||
}).lean();
|
||||
|
||||
if (secretVersion) {
|
||||
secret = await new Secret({
|
||||
...secretVersion,
|
||||
_id: secretVersion?.secret
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!secret) {
|
||||
// case: failed to find personal secret matching criteria
|
||||
// -> find shared secret matching criteria
|
||||
if (version === undefined) {
|
||||
secret = await Secret.findOne({
|
||||
secretBlindIndex,
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
folder: folderId,
|
||||
type: SECRET_SHARED
|
||||
}).lean();
|
||||
} else {
|
||||
const secretVersion = await SecretVersion.findOne({
|
||||
secretBlindIndex,
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
folder: folderId,
|
||||
type: SECRET_SHARED,
|
||||
version
|
||||
}).lean();
|
||||
|
||||
if (secretVersion) {
|
||||
secret = await new Secret({
|
||||
...secretVersion,
|
||||
_id: secretVersion?.secret
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!secret && include_imports) {
|
||||
// if still no secret found search in imported secret and retreive
|
||||
secret = await getAnImportedSecret(secretName, workspaceId.toString(), environment, folderId);
|
||||
secret = await getAnImportedSecret(
|
||||
secretName,
|
||||
workspaceId.toString(),
|
||||
environment,
|
||||
folderId,
|
||||
version
|
||||
);
|
||||
}
|
||||
|
||||
if (!secret) throw SecretNotFoundError();
|
||||
@ -1141,11 +1187,12 @@ const recursivelyExpandSecret = async (
|
||||
const secRefKey = entities[entities.length - 1];
|
||||
|
||||
const val = await fetchCrossEnv(secRefEnv, secRefPath, secRefKey);
|
||||
interpolatedValue = interpolatedValue.replaceAll(interpolationSyntax, val);
|
||||
if (val !== undefined) {
|
||||
interpolatedValue = interpolatedValue.replaceAll(interpolationSyntax, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expandedSec[key] = interpolatedValue;
|
||||
return interpolatedValue;
|
||||
};
|
||||
|
@ -38,6 +38,7 @@ export interface GetSecretParams {
|
||||
type?: "shared" | "personal";
|
||||
authData: AuthData;
|
||||
include_imports?: boolean;
|
||||
version?: number;
|
||||
}
|
||||
|
||||
export interface UpdateSecretParams {
|
||||
|
@ -156,12 +156,20 @@ router.get(
|
||||
integrationAuthController.getIntegrationAuthTeamCityBuildConfigs
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
integrationAuthController.deleteIntegrationAuths
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/:integrationAuthId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
integrationAuthController.deleteIntegrationAuth
|
||||
integrationAuthController.deleteIntegrationAuthById
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Types } from "mongoose";
|
||||
import { generateSecretBlindIndexHelper } from "../helpers";
|
||||
import { SecretVersion } from "../ee/models";
|
||||
import { Folder, ISecret, Secret, SecretImport } from "../models";
|
||||
import { getFolderByPath } from "./FolderService";
|
||||
|
||||
@ -9,7 +10,8 @@ export const getAnImportedSecret = async (
|
||||
secretName: string,
|
||||
workspaceId: string,
|
||||
environment: string,
|
||||
folderId = "root"
|
||||
folderId = "root",
|
||||
version?: number
|
||||
) => {
|
||||
const secretBlindIndex = await generateSecretBlindIndexHelper({
|
||||
secretName,
|
||||
@ -48,10 +50,26 @@ export const getAnImportedSecret = async (
|
||||
});
|
||||
if (importedSecByFid.length === 0) return;
|
||||
|
||||
const secret = await Secret.findOne({
|
||||
workspace: workspaceId,
|
||||
secretBlindIndex
|
||||
}).or(importedSecByFid.map(({ environment, folderId }) => ({ environment, folder: folderId }))).lean()
|
||||
let secret;
|
||||
if (version === undefined) {
|
||||
secret = await Secret.findOne({
|
||||
workspace: workspaceId,
|
||||
secretBlindIndex
|
||||
}).or(importedSecByFid.map(({ environment, folderId }) => ({ environment, folder: folderId }))).lean()
|
||||
} else {
|
||||
const secretVersion = await SecretVersion.findOne({
|
||||
workspace: workspaceId,
|
||||
secretBlindIndex,
|
||||
version
|
||||
}).or(importedSecByFid.map(({ environment, folderId }) => ({ environment, folder: folderId }))).lean();
|
||||
|
||||
if (secretVersion) {
|
||||
secret = await new Secret({
|
||||
...secretVersion,
|
||||
_id: secretVersion.secret,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return secret;
|
||||
};
|
||||
|
@ -7,8 +7,14 @@ export const getUserAgentType = function (userAgent: string | undefined) {
|
||||
return UserAgentType.CLI;
|
||||
} else if (userAgent == UserAgentType.K8_OPERATOR) {
|
||||
return UserAgentType.K8_OPERATOR;
|
||||
} else if (userAgent == UserAgentType.TERRAFORM) {
|
||||
return UserAgentType.TERRAFORM;
|
||||
} else if (userAgent.toLowerCase().includes("mozilla")) {
|
||||
return UserAgentType.WEB;
|
||||
} else if (userAgent.includes(UserAgentType.NODE_SDK)) {
|
||||
return UserAgentType.NODE_SDK;
|
||||
} else if (userAgent.includes(UserAgentType.PYTHON_SDK)) {
|
||||
return UserAgentType.PYTHON_SDK;
|
||||
} else {
|
||||
return UserAgentType.OTHER;
|
||||
}
|
||||
|
@ -108,14 +108,14 @@ export const AddUniversalAuthToIdentityV1 = z.object({
|
||||
})
|
||||
.array()
|
||||
.min(1)
|
||||
.default([{ ipAddress: "0.0.0.0/0" }]),
|
||||
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]),
|
||||
accessTokenTrustedIps: z
|
||||
.object({
|
||||
ipAddress: z.string().trim(),
|
||||
})
|
||||
.array()
|
||||
.min(1)
|
||||
.default([{ ipAddress: "0.0.0.0/0" }]),
|
||||
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]),
|
||||
accessTokenTTL: z.number().int().min(1).refine(value => value !== 0, {
|
||||
message: "accessTokenTTL must have a non zero number",
|
||||
}).default(2592000),
|
||||
|
@ -192,6 +192,13 @@ export const GetIntegrationAuthNorthflankSecretGroupsV1 = z.object({
|
||||
})
|
||||
});
|
||||
|
||||
export const DeleteIntegrationAuthsV1 = z.object({
|
||||
query: z.object({
|
||||
integration: z.string().trim(),
|
||||
workspaceId: z.string().trim()
|
||||
})
|
||||
});
|
||||
|
||||
export const DeleteIntegrationAuthV1 = z.object({
|
||||
params: z.object({
|
||||
integrationAuthId: z.string().trim()
|
||||
|
@ -246,7 +246,15 @@ export const GetSecretByNameRawV3 = z.object({
|
||||
include_imports: z
|
||||
.enum(["true", "false"])
|
||||
.default("true")
|
||||
.transform((value) => value === "true")
|
||||
.transform((value) => value === "true"),
|
||||
version: z
|
||||
.string()
|
||||
.trim()
|
||||
.optional()
|
||||
.transform((value) => value === undefined ? undefined : parseInt(value, 10))
|
||||
.refine((value) => value === undefined || !isNaN(value), {
|
||||
message: "Version must be a number",
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
@ -318,7 +326,15 @@ export const GetSecretByNameV3 = z.object({
|
||||
include_imports: z
|
||||
.enum(["true", "false"])
|
||||
.default("true")
|
||||
.transform((value) => value === "true")
|
||||
.transform((value) => value === "true"),
|
||||
version: z
|
||||
.string()
|
||||
.trim()
|
||||
.optional()
|
||||
.transform((value) => value === undefined ? undefined : parseInt(value, 10))
|
||||
.refine((value) => value === undefined || !isNaN(value), {
|
||||
message: "Version must be a number",
|
||||
})
|
||||
}),
|
||||
params: z.object({
|
||||
secretName: z.string().trim()
|
||||
|
@ -158,7 +158,7 @@ export const CreateServiceTokenV2 = z.object({
|
||||
encryptedKey: z.string().trim(),
|
||||
iv: z.string().trim(),
|
||||
tag: z.string().trim(),
|
||||
expiresIn: z.number(),
|
||||
expiresIn: z.number().nullable().optional(),
|
||||
permissions: z.enum(["read", "write"]).array()
|
||||
})
|
||||
});
|
||||
|
@ -1,4 +0,0 @@
|
||||
FROM alpine
|
||||
RUN apk add --no-cache tini
|
||||
COPY infisical /bin/infisical
|
||||
ENTRYPOINT ["/sbin/tini", "--", "/bin/infisical"]
|
9
cli/docker/alpine
Normal file
@ -0,0 +1,9 @@
|
||||
FROM alpine
|
||||
RUN apk add --no-cache tini
|
||||
|
||||
## Upgrade OpenSSL libraries to mitigate known vulnerabilities as the current Alpine image has not been patched yet.
|
||||
RUN apk update && apk upgrade --no-cache libcrypto3 libssl3
|
||||
|
||||
|
||||
COPY infisical /bin/infisical
|
||||
ENTRYPOINT ["/sbin/tini", "--", "/bin/infisical"]
|
@ -474,6 +474,7 @@ func CallGetRawSecretsV3(httpClient *resty.Client, request GetRawSecretsV3Reques
|
||||
SetBody(request).
|
||||
SetQueryParam("workspaceId", request.WorkspaceId).
|
||||
SetQueryParam("environment", request.Environment).
|
||||
SetQueryParam("secretPath", request.SecretPath).
|
||||
SetQueryParam("include_imports", "false").
|
||||
Get(fmt.Sprintf("%v/v3/secrets/raw", config.INFISICAL_URL))
|
||||
|
||||
|
@ -5,6 +5,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -37,7 +38,8 @@ type Config struct {
|
||||
}
|
||||
|
||||
type InfisicalConfig struct {
|
||||
Address string `yaml:"address"`
|
||||
Address string `yaml:"address"`
|
||||
ExitAfterAuth bool `yaml:"exit-after-auth"`
|
||||
}
|
||||
|
||||
type AuthConfig struct {
|
||||
@ -66,8 +68,9 @@ type SinkDetails struct {
|
||||
}
|
||||
|
||||
type Template struct {
|
||||
SourcePath string `yaml:"source-path"`
|
||||
DestinationPath string `yaml:"destination-path"`
|
||||
SourcePath string `yaml:"source-path"`
|
||||
Base64TemplateContent string `yaml:"base64-template-content"`
|
||||
DestinationPath string `yaml:"destination-path"`
|
||||
}
|
||||
|
||||
func ReadFile(filePath string) ([]byte, error) {
|
||||
@ -107,12 +110,7 @@ func appendAPIEndpoint(address string) string {
|
||||
return address + "/api"
|
||||
}
|
||||
|
||||
func ParseAgentConfig(filePath string) (*Config, error) {
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func ParseAgentConfig(configFile []byte) (*Config, error) {
|
||||
var rawConfig struct {
|
||||
Infisical InfisicalConfig `yaml:"infisical"`
|
||||
Auth struct {
|
||||
@ -123,7 +121,7 @@ func ParseAgentConfig(filePath string) (*Config, error) {
|
||||
Templates []Template `yaml:"templates"`
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(data, &rawConfig); err != nil {
|
||||
if err := yaml.Unmarshal(configFile, &rawConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -205,6 +203,35 @@ func ProcessTemplate(templatePath string, data interface{}, accessToken string)
|
||||
return &buf, nil
|
||||
}
|
||||
|
||||
func ProcessBase64Template(encodedTemplate string, data interface{}, accessToken string) (*bytes.Buffer, error) {
|
||||
// custom template function to fetch secrets from Infisical
|
||||
decoded, err := base64.StdEncoding.DecodeString(encodedTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
templateString := string(decoded)
|
||||
|
||||
secretFunction := secretTemplateFunction(accessToken)
|
||||
funcs := template.FuncMap{
|
||||
"secret": secretFunction,
|
||||
}
|
||||
|
||||
templateName := "base64Template"
|
||||
|
||||
tmpl, err := template.New(templateName).Funcs(funcs).Parse(templateString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &buf, nil
|
||||
}
|
||||
|
||||
type TokenManager struct {
|
||||
accessToken string
|
||||
accessTokenTTL time.Duration
|
||||
@ -219,10 +246,11 @@ type TokenManager struct {
|
||||
newAccessTokenNotificationChan chan bool
|
||||
removeClientSecretOnRead bool
|
||||
cachedClientSecret string
|
||||
exitAfterAuth bool
|
||||
}
|
||||
|
||||
func NewTokenManager(fileDeposits []Sink, templates []Template, clientIdPath string, clientSecretPath string, newAccessTokenNotificationChan chan bool, removeClientSecretOnRead bool) *TokenManager {
|
||||
return &TokenManager{filePaths: fileDeposits, templates: templates, clientIdPath: clientIdPath, clientSecretPath: clientSecretPath, newAccessTokenNotificationChan: newAccessTokenNotificationChan, removeClientSecretOnRead: removeClientSecretOnRead}
|
||||
func NewTokenManager(fileDeposits []Sink, templates []Template, clientIdPath string, clientSecretPath string, newAccessTokenNotificationChan chan bool, removeClientSecretOnRead bool, exitAfterAuth bool) *TokenManager {
|
||||
return &TokenManager{filePaths: fileDeposits, templates: templates, clientIdPath: clientIdPath, clientSecretPath: clientSecretPath, newAccessTokenNotificationChan: newAccessTokenNotificationChan, removeClientSecretOnRead: removeClientSecretOnRead, exitAfterAuth: exitAfterAuth}
|
||||
}
|
||||
|
||||
func (tm *TokenManager) SetToken(token string, accessTokenTTL time.Duration, accessTokenMaxTTL time.Duration) {
|
||||
@ -245,18 +273,26 @@ func (tm *TokenManager) GetToken() string {
|
||||
|
||||
// Fetches a new access token using client credentials
|
||||
func (tm *TokenManager) FetchNewAccessToken() error {
|
||||
clientIDAsByte, err := ReadFile(tm.clientIdPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read client id from file path '%s' due to error: %v", tm.clientIdPath, err)
|
||||
clientID := os.Getenv("INFISICAL_UNIVERSAL_AUTH_CLIENT_ID")
|
||||
if clientID == "" {
|
||||
clientIDAsByte, err := ReadFile(tm.clientIdPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read client id from file path '%s' due to error: %v", tm.clientIdPath, err)
|
||||
}
|
||||
clientID = string(clientIDAsByte)
|
||||
}
|
||||
|
||||
clientSecretAsByte, err := ReadFile(tm.clientSecretPath)
|
||||
if err != nil {
|
||||
if len(tm.cachedClientSecret) == 0 {
|
||||
return fmt.Errorf("unable to read client secret from file and no cached client secret found: %v", err)
|
||||
} else {
|
||||
clientSecretAsByte = []byte(tm.cachedClientSecret)
|
||||
clientSecret := os.Getenv("INFISICAL_UNIVERSAL_CLIENT_SECRET")
|
||||
if clientSecret == "" {
|
||||
clientSecretAsByte, err := ReadFile(tm.clientSecretPath)
|
||||
if err != nil {
|
||||
if len(tm.cachedClientSecret) == 0 {
|
||||
return fmt.Errorf("unable to read client secret from file and no cached client secret found: %v", err)
|
||||
} else {
|
||||
clientSecretAsByte = []byte(tm.cachedClientSecret)
|
||||
}
|
||||
}
|
||||
clientSecret = string(clientSecretAsByte)
|
||||
}
|
||||
|
||||
// remove client secret after first read
|
||||
@ -264,13 +300,10 @@ func (tm *TokenManager) FetchNewAccessToken() error {
|
||||
os.Remove(tm.clientSecretPath)
|
||||
}
|
||||
|
||||
clientId := string(clientIDAsByte)
|
||||
clientSecret := string(clientSecretAsByte)
|
||||
|
||||
// save as cache in memory
|
||||
tm.cachedClientSecret = clientSecret
|
||||
|
||||
err, loginResponse := universalAuthLogin(clientId, clientSecret)
|
||||
err, loginResponse := universalAuthLogin(clientID, clientSecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -354,6 +387,11 @@ func (tm *TokenManager) ManageTokenLifecycle() {
|
||||
}
|
||||
}
|
||||
|
||||
if tm.exitAfterAuth {
|
||||
time.Sleep(25 * time.Second)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if accessTokenRefreshedTime.IsZero() {
|
||||
accessTokenRefreshedTime = tm.accessTokenFetchedTime
|
||||
} else {
|
||||
@ -396,7 +434,14 @@ func (tm *TokenManager) FetchSecrets() {
|
||||
token := tm.GetToken()
|
||||
if token != "" {
|
||||
for _, secretTemplate := range tm.templates {
|
||||
processedTemplate, err := ProcessTemplate(secretTemplate.SourcePath, nil, token)
|
||||
var processedTemplate *bytes.Buffer
|
||||
var err error
|
||||
if secretTemplate.SourcePath != "" {
|
||||
processedTemplate, err = ProcessTemplate(secretTemplate.SourcePath, nil, token)
|
||||
} else {
|
||||
processedTemplate, err = ProcessBase64Template(secretTemplate.Base64TemplateContent, nil, token)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error().Msgf("template engine: unable to render secrets because %s. Will try again on next cycle", err)
|
||||
|
||||
@ -449,12 +494,37 @@ var agentCmd = &cobra.Command{
|
||||
util.HandleError(err, "Unable to parse flag config")
|
||||
}
|
||||
|
||||
if !FileExists(configPath) {
|
||||
log.Error().Msgf("Unable to locate %s. The provided agent config file path is either missing or incorrect", configPath)
|
||||
var agentConfigInBytes []byte
|
||||
|
||||
agentConfigInBase64 := os.Getenv("INFISICAL_AGENT_CONFIG_BASE64")
|
||||
|
||||
if agentConfigInBase64 == "" {
|
||||
data, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
if !FileExists(configPath) {
|
||||
log.Error().Msgf("Unable to locate %s. The provided agent config file path is either missing or incorrect", configPath)
|
||||
return
|
||||
}
|
||||
}
|
||||
agentConfigInBytes = data
|
||||
}
|
||||
|
||||
if agentConfigInBase64 != "" {
|
||||
decodedAgentConfig, err := base64.StdEncoding.DecodeString(agentConfigInBase64)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Unable to decode base64 config file because %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
agentConfigInBytes = decodedAgentConfig
|
||||
}
|
||||
|
||||
if !FileExists(configPath) && agentConfigInBase64 == "" {
|
||||
log.Error().Msgf("No agent config file provided. Please provide a agent config file", configPath)
|
||||
return
|
||||
}
|
||||
|
||||
agentConfig, err := ParseAgentConfig(configPath)
|
||||
agentConfig, err := ParseAgentConfig(agentConfigInBytes)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Unable to prase %s because %v. Please ensure that is follows the Infisical Agent config structure", configPath, err)
|
||||
return
|
||||
@ -471,7 +541,7 @@ var agentCmd = &cobra.Command{
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
filePaths := agentConfig.Sinks
|
||||
tm := NewTokenManager(filePaths, agentConfig.Templates, configUniversalAuthType.ClientIDPath, configUniversalAuthType.ClientSecretPath, tokenRefreshNotifier, configUniversalAuthType.RemoveClientSecretOnRead)
|
||||
tm := NewTokenManager(filePaths, agentConfig.Templates, configUniversalAuthType.ClientIDPath, configUniversalAuthType.ClientSecretPath, tokenRefreshNotifier, configUniversalAuthType.RemoveClientSecretOnRead, agentConfig.Infisical.ExitAfterAuth)
|
||||
|
||||
go tm.ManageTokenLifecycle()
|
||||
go tm.FetchSecrets()
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/Infisical/infisical-merge/packages/models"
|
||||
"github.com/Infisical/infisical-merge/packages/util"
|
||||
"github.com/posthog/posthog-go"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -102,7 +101,7 @@ var exportCmd = &cobra.Command{
|
||||
|
||||
fmt.Print(output)
|
||||
|
||||
Telemetry.CaptureEvent("cli-command:export", posthog.NewProperties().Set("secretsCount", len(secrets)).Set("version", util.CLI_VERSION))
|
||||
// Telemetry.CaptureEvent("cli-command:export", posthog.NewProperties().Set("secretsCount", len(secrets)).Set("version", util.CLI_VERSION))
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ func GetPlainTextSecretsViaMachineIdentity(accessToken string, workspaceId strin
|
||||
getSecretsRequest.SecretPath = secretsPath
|
||||
}
|
||||
|
||||
rawSecrets, err := api.CallGetRawSecretsV3(httpClient, api.GetRawSecretsV3Request{WorkspaceId: workspaceId, SecretPath: environmentName, Environment: environmentName})
|
||||
rawSecrets, err := api.CallGetRawSecretsV3(httpClient, api.GetRawSecretsV3Request{WorkspaceId: workspaceId, SecretPath: secretsPath, Environment: environmentName})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
title: "Get Projects"
|
||||
openapi: "GET /api/v2/organizations/{organizationId}/workspaces"
|
||||
---
|
||||
|
||||
<Warning>
|
||||
This endpoint will be deprecated in the near future in Q1/Q2 2024.
|
||||
|
||||
We recommend switching to using [identities](/documentation/platform/identities/overview).
|
||||
</Warning>
|
||||
---
|
@ -6,6 +6,9 @@ The changelog below reflects new product developments and updates on a monthly b
|
||||
|
||||
## December 2023
|
||||
|
||||
- Released [(machine) identities](https://infisical.com/docs/documentation/platform/identities/overview) and [universal auth](https://infisical.com/docs/documentation/platform/identities/universal-auth) features.
|
||||
- Created new cross-language SDKs for [Python](https://infisical.com/docs/sdks/languages/python), [Node](https://infisical.com/docs/sdks/languages/node), and [Java](https://infisical.com/docs/sdks/languages/java).
|
||||
- Released first version of the [Infisical Agent](https://infisical.com/docs/infisical-agent/overview)
|
||||
- Added ability to [manage folders via CLI](https://infisical.com/docs/cli/commands/secrets).
|
||||
|
||||
## November 2023
|
||||
|
@ -6,7 +6,7 @@ description: "Frequently Asked Questions about contributing to Infisical"
|
||||
Frequently asked questions about contributing to Infisical can be found on this page.
|
||||
If you can't find the answer you are looking for, please create an issue on our GitHub repository or join our Slack channel for additional support.
|
||||
|
||||
<Accordion title="Error building backend (Alpine Linux CDN temporary error)">
|
||||
<Accordion title="Error building Infisical platform backend (Alpine Linux CDN temporary error)">
|
||||
The Alpine Linux CDN may be unavailable/down in your region infrequently (eg. there is an unplanned outage). One possible fix is to add a retry mechanism and a fallback mirrors array to the Dockerfile. You can also use this as an opportunity to pin the Alpine Linux version for Docker to use in case there are issues with the latest version. Ensure to use https for the mirrors.
|
||||
|
||||
#### Make the following changes to the backend Dockerfile
|
@ -1,14 +1,30 @@
|
||||
---
|
||||
title: "Overview"
|
||||
description: "We welcome any contributions to Infisical, big or small."
|
||||
description: "Contributing to the Infisical ecosystem."
|
||||
---
|
||||
|
||||
To set a strong foundation, this section outlines how we, the community and members of Infisical,
|
||||
should approach the development and contribution process.
|
||||
|
||||
## Code-bases
|
||||
Infisical has two major code-bases. One for the platform code, and one for SDKs. The contribution process has some key differences between the two, so we've split the documentation into two sections:
|
||||
|
||||
- The [Infisical Platform](https://github.com/Infisical/infisical), the Infisical platform itself.
|
||||
- The [Infisical SDK](https://github.com/Infisical/sdk), the official Infisical client SDKs.
|
||||
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Infisical Platform" href="/contributing/platform/developing" icon="layer-group" color="#A1B659">
|
||||
The Infisical platform is the core of the Infisical ecosystem.
|
||||
</Card>
|
||||
<Card href="/contributing/sdk/developing" title="Infisical SDK" icon="code" color="#A1B659">
|
||||
The SDKs are the official Infisical client libraries, used by developers to easily interact with the Infisical platform.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Community
|
||||
|
||||
We are building an inclusive community, and this means adhering to the [Code of Conduct](/contributing/code-of-conduct).
|
||||
We are building an inclusive community, and this means adhering to the [Code of Conduct](/contributing/getting-started/code-of-conduct).
|
||||
|
||||
## Bugs and issues
|
||||
|
||||
@ -29,8 +45,10 @@ If you're ever in doubt about whether or not a proposed feature aligns with Infi
|
||||
|
||||
## Writing and submitting code
|
||||
|
||||
Anyone can contribute code to Infisical. To get started, check out the [local development guide](/contributing/developing), make your changes, and submit a pull request to the main repository
|
||||
adhering to the [pull request guide](/contributing/pull-requests).
|
||||
Anyone can contribute code to Infisical. To get started, check out the local development guides for each language.
|
||||
|
||||
- Local development guide for Platform is [here](/contributing/platform/developing).
|
||||
- Local development guide for SDK is [here](/contributing/sdk/developing).
|
||||
|
||||
|
||||
## Licensing
|
||||
@ -38,3 +56,4 @@ adhering to the [pull request guide](/contributing/pull-requests).
|
||||
Most of Infisical's code is under the MIT license, though some paid feature restrictions are covered by a proprietary license.
|
||||
|
||||
Any third party components incorporated into our code are licensed under the original license provided by the applicable component owner.
|
||||
|
@ -19,7 +19,7 @@ You should follow the automatically-generated PR template to fill in the PR desc
|
||||
|
||||
Give a functional overview of how your feature works, including how the user can use the feature. Then share any technical details in an overview of how the PR works.
|
||||
|
||||
As of `06-01-2023`, all PRs created after this date are required to attach a video of you performing the described functionality.
|
||||
As of `06-01-2023`, all PRs created after this date are required to attach a video of you performing the described functionality.
|
||||
|
||||
### Bug Fix PRs
|
||||
|
||||
@ -34,6 +34,8 @@ Once your PR is reviewed, one or two relevant members of the Infisical team shou
|
||||
- Vlad: Frontend, Web UI
|
||||
- Tony: Backend, SDKs, Security
|
||||
- Maidul: Backend, CI/CD, CLI, Kubernetes Operator
|
||||
- Daniel: Frontend, UI/UX, Backend, SDKs
|
||||
|
||||
|
||||
The team member(s) will start by enabling baseline checks to ensure that there are no leaked secrets, new dependencies are clear, and the frontend/backend services start up. Afterward, they will review your PR thoroughly by testing the code and leave any feedback or work in with you to revise the PR up to standard.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 'Local development'
|
||||
description: 'This guide will help you set up and run Infisical in local development.'
|
||||
description: 'This guide will help you set up and run the Infisical platform in local development.'
|
||||
---
|
||||
|
||||
## Fork and clone the repo
|
408
docs/contributing/sdk/developing.mdx
Normal file
@ -0,0 +1,408 @@
|
||||
---
|
||||
title: "Local development"
|
||||
description: "This guide will help you contribute to the Infisical SDK."
|
||||
---
|
||||
|
||||
## Fork and clone the repo
|
||||
|
||||
[Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) the [repository](https://github.com/Infisical/sdk) to your own GitHub account and then [clone](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) it to your local device.
|
||||
|
||||
Once, you've done that, create a new branch:
|
||||
|
||||
```console
|
||||
git checkout -b MY_BRANCH_NAME
|
||||
```
|
||||
|
||||
## Set up environment variables
|
||||
|
||||
Start by creating a .env file at the root of the Infisical directory then copy the contents of the file below into the .env file.
|
||||
|
||||
<Accordion title=".env file content">
|
||||
```env
|
||||
# This is required for running tests locally.
|
||||
# Rename this file to ".env" and fill in the values below.
|
||||
|
||||
# Please make sure that the machine identity has access to the project you are testing in.
|
||||
# https://infisical.com/docs/documentation/platform/identities/universal-auth
|
||||
INFISICAL_UNIVERSAL_CLIENT_ID=MACHINE_IDENTITY_CLIENT_ID
|
||||
INFISICAL_UNIVERSAL_CLIENT_SECRET=MACHINE_IDENTITY_CLIENT_SECRET
|
||||
|
||||
# The ID of the Infisical project where we will create the test secrets.
|
||||
# NOTE: The project must have a dev environment. (This is created by default when you create a project.)
|
||||
INFISICAL_PROJECT_ID=INFISICAL_TEST_PROJECT_ID
|
||||
|
||||
# The Infisical site URL. If you are testing with a local Infisical instance, then this should be set to "http://localhost:8080".
|
||||
INFISICAL_SITE_URL=https://app.infisical.com
|
||||
|
||||
````
|
||||
</Accordion>
|
||||
|
||||
<Warning>
|
||||
The above values are required for running tests locally. Before opening a pull request, make sure to run `cargo test` to ensure that all tests pass.
|
||||
</Warning>
|
||||
|
||||
|
||||
## Guidelines
|
||||
|
||||
### Predictable and consistent
|
||||
When adding new functionality (such as new functions), it's very important that the functionality is added to _all_ the SDK's. This is to ensure that the SDK's are predictable and consistent across all languages. If you are adding new functionality, please make sure to add it to all the SDK's.
|
||||
|
||||
### Handling errors
|
||||
Error handling is very important when writing SDK's. We want to make sure that the SDK's are easy to use, and that the user gets a good understanding of what went wrong when something fails. When adding new functionality, please make sure to add proper error handling. [Read more about error handling here](#error-handling).
|
||||
|
||||
### Tests
|
||||
If you add new functionality or modify existing functionality, please write tests thats properly cover the new functionality. You can run tests locally by running `cargo test` from the root directory. You must always run tests before opening a pull request.
|
||||
|
||||
### Code style
|
||||
Please follow the default rust styling guide when writing code for the base SDK. [Read more about rust code style here](https://doc.rust-lang.org/nightly/style-guide/#the-default-rust-style).
|
||||
|
||||
|
||||
## Prerequisites for contributing
|
||||
|
||||
### Understanding the terms
|
||||
|
||||
In the guide we use some terms that might be unfamiliar to you. Here's a quick explanation of the terms we use:
|
||||
- **Base SDK**: The base SDK is the SDK that all other SDK's are built on top of. The base SDK is written in Rust, and is responsible for executing commands and parsing the input and output to and from JSON.
|
||||
- **Commands**: Commands are what's being sent from the target language to the command handler. The command handler uses the command to execute the corresponding function in the base SDK. Commands are in reality just a JSON string that tells the command handler what function to execute, and what input to use.
|
||||
- **Command handler**: The command handler is the part of the base SDK that takes care of executing commands. It also takes care of parsing the input and output to and from JSON.
|
||||
- **Target language**: The target language refers to the actual SDK code. For example, the [Node.js SDK](https://www.npmjs.com/package/@infisical/sdk) is a "target language", and so is the [Python SDK](https://pypi.org/project/infisical-python/).
|
||||
|
||||
|
||||
### Understanding the execution flow
|
||||
After the target language SDK is initiated, it uses language-specific bindings to interact with the base SDK.
|
||||
These bindings are instantiated, setting up the interface for command execution. A client within the command handler is created, which issues commands to the base SDK.
|
||||
When a command is executed, it is first validated. If valid, the command handler locates the corresponding command to perform. If the command executes successfully, the command handler returns the output to the target language SDK, where it is parsed and returned to the user.
|
||||
If the command handler fails to validate the input, an error will be returned to the target language SDK.
|
||||
|
||||
|
||||
<Frame caption="Execution flow diagram for the SDK from the target language to the base SDK. The execution flow is the same for all target languages.">
|
||||
<img height="640" width="520" src="/images/sdk-flow.png" />
|
||||
</Frame>
|
||||
|
||||
|
||||
|
||||
### Rust knowledge
|
||||
|
||||
Contributing to the SDK requires intermediate to advanced knowledge of Rust concepts such as lifetimes, traits, generics, and async/await _(futures)_, and more.
|
||||
|
||||
### Rust setup
|
||||
The base SDK is written in rust. Therefore you must have rustc and cargo installed. You can install rustc and cargo by following the instructions [here](https://www.rust-lang.org/tools/install).
|
||||
|
||||
You shouldn't have to use the rust cross compilation toolchain, as all compilation is done through a collection of Github Actions. However. If you need to test cross compilation, please do so with Github Actions.
|
||||
|
||||
### Tests
|
||||
If you add new functionality or modify existing functionality, please write tests thats properly cover the new functionality. You can run tests locally by running `cargo test` from the root directory.
|
||||
|
||||
### Language-specific crates
|
||||
The language-specific crates should ideally never have to be modified, as they are simply a wrapper for the `infisical-json` crate, which executes "commands" from the base SDK. If you need to create a new target-language specific crate, please try to create native bindings for the target language. Some languages don't have direct support for native bindings (Java as an example). In those cases we can use the C bindings (`crates/infisical-c`) in the target language.
|
||||
|
||||
|
||||
|
||||
|
||||
## Generate types
|
||||
Having almost seemless type safety from the base SDK to the target language is critical, as writing types for each language has a lot of drawbacks such as duplicated code, and lots of overhead trying to keep the types up-to-date and in sync across a large collection of languages. Therefore we decided to use [QuickType](https://quicktype.io/) and [Serde](https://serde.rs/) to help us generate types for each language. In our Rust base SDK (`crates/infisical`), we define all the inputs/outputs.
|
||||
|
||||
If you are interested in reading about QuickType works under the hood, you can [read more here](http://blog.quicktype.io/under-the-hood/).
|
||||
|
||||
This is an example of a type defined in Rust (both input and output). For this to become a generated type, you'll need to add it to our schema generator. More on that further down.
|
||||
```rust
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
// Input:
|
||||
pub struct CreateSecretOptions {
|
||||
pub environment: String, // environment
|
||||
pub secret_comment: Option<String>, // secretComment
|
||||
pub path: Option<String>, // secretPath
|
||||
pub secret_value: String, // secretValue
|
||||
pub skip_multiline_encoding: Option<bool>, // skipMultilineEncoding
|
||||
pub r#type: Option<String>, // shared / personal
|
||||
pub project_id: String, // workspaceId
|
||||
pub secret_name: String, // secretName (PASSED AS PARAMETER IN REQUEST)
|
||||
}
|
||||
|
||||
// Output:
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateSecretResponse {
|
||||
pub secret: Secret, // "Secret" is defined elsewhere.
|
||||
}
|
||||
````
|
||||
|
||||
### Adding input types to the schema generator
|
||||
|
||||
You will _only_ have to define outputs in our schema generator, then QuickType will take care of the rest behind the scenes. You can find the Rust crate that takes care of type generation here: `crates/sdk-schemas/src/main.rs`.
|
||||
|
||||
Simply add the output _(also called response)_, to the `write_schema_for_response!` macro. This will let QuickType know that it should generate types for the given structs. The main function will look something like this:
|
||||
|
||||
```rust
|
||||
fn main() -> Result<()> {
|
||||
// Input types for new Client
|
||||
write_schema_for!(infisical_json::client::ClientSettings);
|
||||
// Input types for Client::run_command
|
||||
write_schema_for!(infisical_json::command::Command);
|
||||
|
||||
// Output types for Client::run_command
|
||||
// Only add structs which are direct results of SDK commands.
|
||||
write_schema_for_response! {
|
||||
infisical::manager::secrets::GetSecretResponse,
|
||||
infisical::manager::secrets::ListSecretsResponse,
|
||||
infisical::manager::secrets::UpdateSecretResponse,
|
||||
infisical::manager::secrets::DeleteSecretResponse,
|
||||
infisical::manager::secrets::CreateSecretResponse, // <-- This is the output from the above example!
|
||||
infisical::auth::AccessTokenSuccessResponse
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Generating the types for the target language
|
||||
|
||||
Once you've added the output to the schema generator, you can generate the types for the target language by running the following command from the root directory:
|
||||
|
||||
```console
|
||||
$ npm install
|
||||
$ npm run schemas
|
||||
```
|
||||
|
||||
<Warning>If you change any of the structs defined in the base SDK, you will need to run this script to re-generate the types.</Warning>
|
||||
|
||||
This command will run the `schemas.ts` file found in the `support/scripts` folder. If you are adding a new language, it's important that you add the language to the code.
|
||||
|
||||
This is an example of how how we generate types for Node.js:
|
||||
|
||||
```ts
|
||||
const ts = await quicktype({
|
||||
inputData,
|
||||
lang: "typescript",
|
||||
rendererOptions: {}
|
||||
});
|
||||
await ensureDir("./languages/node/src/infisical_client");
|
||||
writeToFile("./languages/node/src/infisical_client/schemas.ts", ts.lines);
|
||||
```
|
||||
|
||||
## Building bindings
|
||||
We've tried to streamline the building process as much as possible. So you shouldn't have to worry much about building bindings, as it should just be a few commands.
|
||||
|
||||
### Node.js
|
||||
Building bindings for Node.js is very straight foward. The command below will generate NAPI bindings for Node.js, and move the bindings to the correct folder. We use [NAPI-RS](https://napi.rs/) to generate the bindings.
|
||||
|
||||
```console
|
||||
$ cd languages/node
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
### Python
|
||||
To generate and use python bindings you will need to run the following commands.
|
||||
The Python SDK is located inside the crates folder. This is a limitation of the maturin tool, forcing us to structure the project in this way.
|
||||
|
||||
```console
|
||||
$ pip install -U pip maturin
|
||||
$ cd crates/infisical-py
|
||||
$ python3 -m venv .venv
|
||||
$ source .venv/bin/activate
|
||||
$ maturin develop
|
||||
```
|
||||
|
||||
<Warning>
|
||||
After running the commands above, it's very important that you rename the generated .so file to `infisical_py.so`. After renaming it you also need to move it into the root of the `crates/infisical-py` folder.
|
||||
</Warning>
|
||||
|
||||
### Java
|
||||
Java uses the C bindings to interact with the base SDK. To build and use the C bindings in Java, please follow the instructions below.
|
||||
|
||||
```console
|
||||
$ cd crates/infisical-c
|
||||
$ cargo build --release
|
||||
$ cd ../../languages/java
|
||||
```
|
||||
<Warning>
|
||||
After generating the C bindings, the generated .so or .dll has been created in the `/target` directory at the root of the project.
|
||||
You have to manually move the generated file into the `languages/java/src/main/resources` directory.
|
||||
</Warning>
|
||||
|
||||
## Error handling
|
||||
|
||||
### Error handling in the base SDK
|
||||
|
||||
The base SDK should never panic. If an error occurs, we should return a `Result` with an error message. We have a custom Result type defined in the `error.rs` file in the base SDK.
|
||||
|
||||
All our errors are defined in an enum called `Error`. The `Error` enum is defined in the `error.rs` file in the base SDK. The `Error` enum is used in the `Result` type, which is used as the return type for all functions in the base SDK.
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
// Secret not found
|
||||
#[error("Secret with name '{}' not found.", .secret_name)]
|
||||
SecretNotFound { secret_name: String },
|
||||
|
||||
// .. other errors
|
||||
|
||||
// Errors that are not specific to the base SDK.
|
||||
#[error(transparent)]
|
||||
Reqwest(#[from] reqwest::Error),
|
||||
#[error(transparent)]
|
||||
Serde(#[from] serde_json::Error),
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
```
|
||||
|
||||
### Returning an error
|
||||
|
||||
You can find many examples of how we return errors in the SDK code. A relevant example is for creating secrets, which can be found in `crates/infisical/src/api/secrets/create_secret.rs`. When the error happened due to a request error to our API, we have an API error handler. This prevents duplicate code and keeps error handling consistent across the SDK. You can find the api error handler in the `error.rs` file.
|
||||
|
||||
### Error handling in the target language SDK's.
|
||||
|
||||
All data sent to the target language SDK has the same format. The format is an object with 3 fields: `success (boolean)`, `data (could be anything or nothing)`, and `errorMessage (string or null)`.
|
||||
|
||||
The `success` field is used to determine if the request was successful or not. The `data` field is used to return data from the SDK. The `errorMessage` field is used to return an error message if the request was not successful.
|
||||
|
||||
This means that if the success if false or if the error message is not null, something went wrong and we should throw an error on the target-language level, with the error message.
|
||||
|
||||
## Command handler
|
||||
|
||||
### What is the command handler
|
||||
|
||||
The command handler (the `infisical-json` crate), takes care of executing commands sent from the target language. It also takes care of parsing the input and output to and from JSON. The command handler is the only part of the base SDK that should be aware of JSON. The rest of the base SDK should be completely unaware of JSON, and only work with the Rust structs defined in the base SDK.
|
||||
|
||||
The command handler exposes a function called `run_command`, which is what we use in the target language to execute commands. The function takes a json string as input, and returns a json string as output. We use helper functions generated by QuickType to convert the input and output to and from JSON.
|
||||
|
||||
### Creating new SDK methods
|
||||
|
||||
Creating new commands is necessary when adding new methods to the SDK's. Defining a new command is a 3-step process in most cases.
|
||||
|
||||
#### 1. Define the input and output structs
|
||||
|
||||
Earlier in this guide, we defined the input and output structs for the `CreateSecret` command. We will use that as an example here as well.
|
||||
|
||||
#### 2. Creating the method in the base SDK
|
||||
|
||||
The first step is to create the method in the base SDK. This step will be different depending on what method you are adding. In this example we're going to assume you're adding a function for creating a new secret.
|
||||
|
||||
After you created the function for creating the secret, you'll need need to add it to the ClientSecrets implementation. We do it this way to keep the code organized and easy to read. The ClientSecrets struct is located in the `crates/infisical/src/manager/secrets.rs` file.
|
||||
|
||||
```rust
|
||||
pub struct ClientSecrets<'a> {
|
||||
pub(crate) client: &'a mut crate::Client,
|
||||
}
|
||||
|
||||
impl<'a> ClientSecrets<'a> {
|
||||
pub async fn create(&mut self, input: &CreateSecretOptions) -> Result<CreateSecretResponse> {
|
||||
create_secret(self.client, input).await // <-- This is the function you created!
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Client {
|
||||
pub fn secrets(&'a mut self) -> ClientSecrets<'a> {
|
||||
ClientSecrets { client: self }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Define a new command
|
||||
|
||||
We define new commands in the `crates/infisical-json/src/command.rs` file. The `Command` enum is what we use to define new commands.
|
||||
|
||||
In the codesnippet below we define a new command called `CreateSecret`. The `CreateSecret` command takes a `CreateSecretOptions` struct as input. We don't have to define the output, because QuickType's converter helps us with figuring out the return type for each command.
|
||||
|
||||
````rust
|
||||
```rust
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
pub enum Command {
|
||||
GetSecret(GetSecretOptions),
|
||||
ListSecrets(ListSecretsOptions),
|
||||
CreateSecret(CreateSecretOptions), // <-- The new command!
|
||||
UpdateSecret(UpdateSecretOptions),
|
||||
DeleteSecret(DeleteSecretOptions),
|
||||
}
|
||||
````
|
||||
|
||||
#### 4. Add the command to the command handler
|
||||
|
||||
After defining the command, we need to add it to the command handler itself. This takes place in the `crates/infisical-json/src/client.rs` file. The `run_command` function is what we use to execute commands.
|
||||
|
||||
In the Client implementation we try to parse the JSON string into a `Command` enum. If the parsing is successful, we match the command and execute the corresponding function.
|
||||
|
||||
```rust
|
||||
match cmd {
|
||||
Command::GetSecret(req) => self.0.secrets().get(&req).await.into_string(),
|
||||
Command::ListSecrets(req) => self.0.secrets().list(&req).await.into_string(),
|
||||
Command::UpdateSecret(req) => self.0.secrets().update(&req).await.into_string(),
|
||||
Command::DeleteSecret(req) => self.0.secrets().delete(&req).await.into_string(),
|
||||
|
||||
// This is the new command:
|
||||
Command::CreateSecret(req) => self.0.secrets().create(&req).await.into_string(),
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. Implementing the new command in the target language SDK's
|
||||
|
||||
We did it! We've now added a new command to the base SDK. The last step is to implement the new command in the target language SDK's. The process is a little different from language to language, but in this example we're going to assume that we're adding a new command to the Node.js SDK.
|
||||
|
||||
First you'll need to generate the new type schemas, we added a new command, input struct, and output struct. [Read more about generating types here](#generating-the-types-for-the-target-language).
|
||||
|
||||
Secondly you need to build the new node bindings so we can use the new functionality in the Node.js SDK. You can do this by running the following command from the `languages/node` directory:
|
||||
|
||||
```console
|
||||
$ npm install
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
The build command will execute a build script in the `infisical-napi` crate, and move the generated bindings to the appropriate folder.
|
||||
|
||||
After building the new bindings, you can access the new functionality in the Node.js SDK source.
|
||||
|
||||
```ts
|
||||
// 'binding' is a js file that makes it easier to access the methods in the bindings. (it's auto generated when running npm run build)
|
||||
import * as rust from "../../binding";
|
||||
// We can import the newly generated types from the schemas.ts file. (Generated with QuickType!)
|
||||
import type { CreateSecretOptions, CreateSecretResponse } from "./schemas";
|
||||
// This is the QuickType converter that we use to create commands with! It takes care of all JSON parsing and serialization.
|
||||
import { Convert, ClientSettings } from "./schemas";
|
||||
|
||||
export class InfisicalClient {
|
||||
#client: rust.Client;
|
||||
|
||||
constructor(settings: ClientSettings) {
|
||||
const settingsJson = settings == null ? null : Convert.clientSettingsToJson(settings);
|
||||
this.#client = new rust.InfisicalClient(settingsJson);
|
||||
}
|
||||
|
||||
// ... getSecret
|
||||
// ... listSecrets
|
||||
// ... updateSecret
|
||||
// ... deleteSecret
|
||||
|
||||
async createSecret(options: CreateSecretOptions): Promise<CreateSecretResponse["secret"]> {
|
||||
// The runCommand will return a JSON string, which we can parse into a CreateSecretResponse.
|
||||
const command = await this.#client.runCommand(
|
||||
Convert.commandToJson({
|
||||
createSecret: options
|
||||
})
|
||||
);
|
||||
const response = Convert.toResponseForCreateSecretResponse(command); // <-- This is the QuickType converter in action!
|
||||
|
||||
// If the response is not successful or the data is null, we throw an error.
|
||||
if (!response.success || response.data == null) {
|
||||
throw new Error(response.errorMessage ?? "Something went wrong");
|
||||
}
|
||||
|
||||
// To make it easier to work with the response, we return the secret directly.
|
||||
return response.data.secret;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And that's it! We've now added a new command to the base SDK, and implemented it in the Node.js SDK. The process is very similar for all other languages, but the code will look a little different.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The SDK has a lot of moving parts, and it can be a little overwhelming at first. But once you get the hang of it, it's actually quite simple. If you have any questions, feel free to reach out to us on [Slack](https://infisical.com/slack), or [open an issue](https://github.com/Infisical/sdk/issues) on GitHub.
|
@ -13,7 +13,8 @@ Prerequisites:
|
||||
|
||||
Follow the instructions for your language use the SDK for it:
|
||||
|
||||
- [Node SDK](https://github.com/Infisical/infisical-node)
|
||||
- [Python SDK](https://github.com/Infisical/infisical-python)
|
||||
- [Node SDK](https://infisical.com/docs/sdks/languages/node)
|
||||
- [Python SDK](https://infisical.com/docs/sdks/languages/python)
|
||||
- [Java SDK](https://infisical.com/docs/sdks/languages/java)
|
||||
|
||||
Missing a language? [Throw in a request](https://github.com/Infisical/infisical/issues).
|
@ -240,12 +240,6 @@ At this stage, you know how to use the Infisical-Vercel integration to sync prod
|
||||
|
||||
Check out the [security guide](/security/overview).
|
||||
</Accordion>
|
||||
<Accordion title="Is there way to retain end-to-end encryption for syncing production secrets to Vercel?">
|
||||
Yes. You can also use the Infisical [Node SDK](https://github.com/Infisical/infisical-node) to fetch secrets back to your Next.js app
|
||||
in both development and production.
|
||||
|
||||
Depending on how you use it, however, it may require certain pages to be server-side rendered.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
See also:
|
||||
|
@ -4,8 +4,7 @@ description: "Programmatically interact with Infisical"
|
||||
---
|
||||
|
||||
<Note>
|
||||
Currently, identities can only be used to make authenticated requests to the Infisical API and do not work with any clients such as [Node SDK](https://github.com/Infisical/infisical-node)
|
||||
, [Python SDK](https://github.com/Infisical/infisical-python), CLI, K8s operator, Terraform Provider, etc.
|
||||
Currently, identities can only be used to make authenticated requests to the Infisical API and SDKs. They do not work with clients such as CLI, K8s Operator, Terraform Provider, etc.
|
||||
|
||||
We will be releasing compatibility with it across clients in the coming quarter.
|
||||
</Note>
|
||||
|
@ -12,8 +12,8 @@ This means that updating the value of a base secret propagates directly to other
|
||||
Currently, the secret referencing feature is only supported by the
|
||||
[Infisical CLI](/cli/overview) and [native integrations](/integrations/overview).
|
||||
|
||||
We intend to add support for it to the [Node SDK](https://github.com/Infisical/infisical-node)
|
||||
and [Python SDK](https://github.com/Infisical/infisical-python) this quarter.
|
||||
We intend to add support for it to the [Node SDK](https://infisical.com/docs/sdks/languages/node),
|
||||
[Python SDK](https://infisical.com/docs/sdks/languages/python), and [Java SDK](https://infisical.com/docs/sdks/languages/java) this quarter.
|
||||
</Note>
|
||||
|
||||

|
||||
|
@ -10,97 +10,97 @@ description: "Configure Azure SAML for Infisical SSO"
|
||||
then you should contact team@infisical.com to purchase an enterprise license to use it.
|
||||
</Info>
|
||||
|
||||
1. In Infisical, head over to your organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
Next, copy the **Reply URL (Assertion Consumer Service URL)** and **Identifier (Entity ID)** to use when configuring the Azure SAML application.
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head over to your organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
|
||||

|
||||
Next, copy the **Reply URL (Assertion Consumer Service URL)** and **Identifier (Entity ID)** to use when configuring the Azure SAML application.
|
||||
|
||||
2. In the Azure Portal, navigate to the Azure Active Directory and select **Enterprise applications**. On this screen, select
|
||||
**+ New application**.
|
||||

|
||||
</Step>
|
||||
<Step title="Create a SAML application in Azure">
|
||||
In the Azure Portal, navigate to the Azure Active Directory and select **Enterprise applications**. On this screen, select **+ New application**.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
On the next screen, press the **+ Create your own application** button.
|
||||
Give the application a unique name like Infisical; choose the "Integrate any other application you don't find in the gallery (Non-gallery)"
|
||||
option and hit the **Create** button.
|
||||
|
||||
2. On the next screen, press the **+ Create your own application** button.
|
||||
Give the application a unique name like Infisical; choose the "Integrate any other application you don't find in the gallery (Non-gallery)"
|
||||
option and hit the **Create** button.
|
||||

|
||||
|
||||

|
||||
On the application overview screen, select **Single sign-on** from the left sidebar. From there, select the **SAML** single sign-on method.
|
||||
|
||||
3. On the application overview screen, select **Single sign-on** from the left sidebar. From there,
|
||||
select the **SAML** single sign-on method.
|
||||

|
||||
|
||||

|
||||
Next, select **Edit** in the **Basic SAML Configuration** section and add/set the **Identifier (Entity ID)** to **Entity ID** and add/set the **Reply URL (Assertion Consumer Service URL)** to **ACS URL** from step 1.
|
||||
|
||||
4. Next, select **Edit** in the **Basic SAML Configuration** section and add/set the **Identifier (Entity ID)**
|
||||
to **Entity ID** and add/set the **Reply URL (Assertion Consumer Service URL)** to **ACS URL** from step 1.
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
<Note>
|
||||
If you're self-hosting Infisical, then you will want to replace
|
||||
`https://app.infisical.com` with your own domain.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
If you're self-hosting Infisical, then you will want to replace
|
||||
`https://app.infisical.com` with your own domain.
|
||||
</Note>
|
||||
Back in the **Set up Single Sign-On with SAML** screen, select **Edit** in the **Attributes & Claims** section and configure the following map:
|
||||
|
||||
5. Back in the **Set up Single Sign-On with SAML** screen, select **Edit** in the **Attributes & Claims** section and configure the following map:
|
||||
- `email -> user.userprinciplename`
|
||||
- `firstName -> user.firstName`
|
||||
- `lastName -> user.lastName`
|
||||
|
||||
- `email -> user.userprinciplename`
|
||||
- `firstName -> user.firstName`
|
||||
- `lastName -> user.lastName`
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
Back in the **Set up Single Sign-On with SAML** screen, select **Edit** in the **SAML Certificates** section and set the **Signing Option** field to **Sign SAML response and assertion**.
|
||||
|
||||
6. Back in the **Set up Single Sign-On with SAML** screen, select **Edit** in the **SAML Certificates** section and set the **Signing Option** field to **Sign SAML response and assertion**.
|
||||

|
||||
|
||||

|
||||

|
||||
</Step>
|
||||
<Step title="Retrieve Identity Provider (IdP) Information from Okta">
|
||||
In the **Set up Single Sign-On with SAML** screen, copy the **Login URL** and **SAML Certificate** to use when finishing configuring Azure SAML in Infisical.
|
||||
|
||||

|
||||

|
||||
|
||||
7. Get IdP values:
|
||||
In the **Properties** screen, copy the **Application ID** to use when finishing configuring Azure SAML in Infisical.
|
||||
|
||||
In the **Set up Single Sign-On with SAML** screen, copy the **Login URL** and **SAML Certificate** to use when finishing configuring Azure SAML in Infisical.
|
||||

|
||||
</Step>
|
||||
<Step title="Finish configuring SAML in Infisical">
|
||||
Back in Infisical, set **Login URL**, **Azure Application ID**, and **SAML Certificate** from step 3. Once you've done that, press **Update** to complete the required configuration.
|
||||
|
||||

|
||||

|
||||
|
||||
In the **Properties** screen, copy the **Application ID** to use when finishing configuring Azure SAML in Infisical.
|
||||
<Note>
|
||||
When pasting the certificate into Infisical, you'll want to retain `-----BEGIN
|
||||
CERTIFICATE-----` and `-----END CERTIFICATE-----` at the first and last line
|
||||
of the text area respectively.
|
||||
|
||||

|
||||
Having trouble?, try copying the X509 certificate information from the Federation Metadata XML file in Azure.
|
||||
|
||||
Back in Infisical, set **Login URL**, **Azure Application ID**, and **SAML Certificate** from above. Once you've done that, press **Update** to complete the required configuration.
|
||||
</Note>
|
||||
</Step>
|
||||
<Step title="Assign users in Azure to the application">
|
||||
Back in Azure, navigate to the **Users and groups** tab and select **+ Add user/group** to assign access to the login with SSO application on a user or group-level.
|
||||
|
||||

|
||||
</Step>
|
||||
<Step title="Enable SAML SSO in Infisical">
|
||||
Enabling SAML SSO enforces all members in your organization to only be able to log into Infisical via Azure.
|
||||
|
||||

|
||||
|
||||
<Note>
|
||||
When pasting the certificate into Infisical, you'll want to retain `-----BEGIN
|
||||
CERTIFICATE-----` and `-----END CERTIFICATE-----` at the first and last line
|
||||
of the text area respectively.
|
||||
|
||||
Having trouble?, try copying the X509 certificate information from the Federation Metadata XML file in Azure.
|
||||
|
||||
</Note>
|
||||
|
||||
7. Assignments
|
||||
|
||||
Back in Azure, navigate to the **Users and groups** tab and select **+ Add user/group** to assign access to the login with SSO application on a user or group-level.
|
||||

|
||||
|
||||
8. Return to Infisical and enable SAML SSO.
|
||||
|
||||
Enabling SAML SSO enforces all members in your organization to only be able to log into Infisical via Azure.
|
||||
|
||||

|
||||

|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
If you're configuring SAML SSO on a self-hosted instance of Infisical, make sure to
|
||||
set the `JWT_PROVIDER_AUTH_SECRET` and `SITE_URL` environment variable for it to work:
|
||||
set the `AUTH_SECRET` and `SITE_URL` environment variable for it to work:
|
||||
|
||||
- `JWT_PROVIDER_AUTH_SECRET`: This is secret key used for signing and verifying JWT. This could be a randomly-generated 256-bit hex string.
|
||||
- `AUTH_SECRET`: A secret key used for signing and verifying JWT. This can be a random 32-byte base64 string generated with `openssl rand -base64 32`.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
</Note>
|
||||
|
||||
|
||||
</Note>
|
@ -5,38 +5,39 @@ description: "Configure GitHub SSO for Infisical"
|
||||
|
||||
Using GitHub SSO on a self-hosted instance of Infisical requires configuring an OAuth2 application in GitHub and registering your instance with it.
|
||||
|
||||
## Create an OAuth application in GitHub
|
||||
<Steps>
|
||||
<Step title="Create an OAuth application in GitHub">
|
||||
Navigate to your user Settings > Developer settings > OAuth Apps to create a new GitHub OAuth application.
|
||||
|
||||
Navigate to your user Settings > Developer settings > OAuth Apps to create a new GitHub OAuth application.
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
Create the OAuth application. As part of the form, set the **Homepage URL** to your self-hosted domain `https://your-domain.com`
|
||||
and the **Authorization callback URL** to `https://your-domain.com/api/v1/sso/github`.
|
||||
|
||||
Create the OAuth application. As part of the form, set the **Homepage URL** to your self-hosted domain `https://your-domain.com`
|
||||
and the **Authorization callback URL** to `https://your-domain.com/api/v1/sso/github`.
|
||||

|
||||
|
||||

|
||||
<Note>
|
||||
If you have a GitHub organization, you can create an OAuth application under it
|
||||
in your organization Settings > Developer settings > OAuth Apps > New Org OAuth App.
|
||||
</Note>
|
||||
</Step>
|
||||
<Step title="Add your OAuth application credentials to Infisical">
|
||||
Obtain the **Client ID** and generate a new **Client Secret** for your GitHub OAuth application.
|
||||
|
||||
<Note>
|
||||
If you have a GitHub organization, you can create an OAuth application under it
|
||||
in your organization Settings > Developer settings > OAuth Apps > New Org OAuth App.
|
||||
</Note>
|
||||

|
||||
|
||||
## Add your OAuth application credentials to Infisical
|
||||
Back in your Infisical instance, make sure to set the following environment variables:
|
||||
|
||||
Obtain the **Client ID** and generate a new **Client Secret** for your GitHub OAuth application.
|
||||
|
||||

|
||||
|
||||
Back in your Infisical instance, make sure to set the following environment variables:
|
||||
|
||||
- `CLIENT_ID_GITHUB_LOGIN`: The **Client ID** of your GitHub OAuth application.
|
||||
- `CLIENT_SECRET_GITHUB_LOGIN`: The **Client Secret** of your GitHub OAuth application.
|
||||
- `JWT_PROVIDER_AUTH_SECRET`: A secret key used for signing and verifying JWT. This could be a randomly-generated 256-bit hex string.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
|
||||
Once added, restart your Infisical instance and log in with GitHub.
|
||||
- `CLIENT_ID_GITHUB_LOGIN`: The **Client ID** of your GitHub OAuth application.
|
||||
- `CLIENT_SECRET_GITHUB_LOGIN`: The **Client Secret** of your GitHub OAuth application.
|
||||
- `AUTH_SECRET`: A secret key used for signing and verifying JWT. This can be a random 32-byte base64 string generated with `openssl rand -base64 32`.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
|
||||
Once added, restart your Infisical instance and log in with GitHub.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## FAQ
|
||||
|
||||
@ -45,7 +46,7 @@ Once added, restart your Infisical instance and log in with GitHub.
|
||||
It is likely that you have misconfigured your self-hosted instance of Infisical. You should:
|
||||
|
||||
- Check that you have set the `CLIENT_ID_GITHUB_LOGIN`, `CLIENT_SECRET_GITHUB_LOGIN`,
|
||||
`JWT_PROVIDER_AUTH_SECRET`, and `SITE_URL` environment variables.
|
||||
`AUTH_SECRET`, and `SITE_URL` environment variables.
|
||||
- Check that the **Authorization callback URL** specified in GitHub matches the `SITE_URL` environment variable.
|
||||
For example, if the former is `https://app.infisical.com/api/v1/sso/github` then the latter should be `https://app.infisical.com`.
|
||||
</Accordion>
|
||||
|
@ -5,38 +5,39 @@ description: "Configure GitLab SSO for Infisical"
|
||||
|
||||
Using GitLab SSO on a self-hosted instance of Infisical requires configuring an OAuth application in GitLab and registering your instance with it.
|
||||
|
||||
## Create an OAuth application in GitLab
|
||||
<Steps>
|
||||
<Step title="Create an OAuth application in GitLab">
|
||||
Navigate to your user Settings > Applications to create a new GitLab application.
|
||||
|
||||
Navigate to your user Settings > Applications to create a new GitLab application.
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
Create the application. As part of the form, set the **Redirect URI** to `https://your-domain.com/api/v1/sso/gitlab`.
|
||||
Note that only `read_user` is required as part of the **Scopes** configuration.
|
||||
|
||||
Create the application. As part of the form, set the **Redirect URI** to `https://your-domain.com/api/v1/sso/gitlab`.
|
||||
Note that only `read_user` is required as part of the **Scopes** configuration.
|
||||

|
||||
|
||||

|
||||
<Note>
|
||||
If you have a GitLab group, you can create an OAuth application under it
|
||||
in your group Settings > Applications.
|
||||
</Note>
|
||||
</Step>
|
||||
<Step title="Add your OAuth application credentials to Infisical">
|
||||
Obtain the **Application ID** and **Secret** for your GitLab application.
|
||||
|
||||
<Note>
|
||||
If you have a GitLab group, you can create an OAuth application under it
|
||||
in your group Settings > Applications.
|
||||
</Note>
|
||||

|
||||
|
||||
## Add your OAuth application credentials to Infisical
|
||||
Back in your Infisical instance, make sure to set the following environment variables:
|
||||
|
||||
Obtain the **Application ID** and **Secret** for your GitLab application.
|
||||
|
||||

|
||||
|
||||
Back in your Infisical instance, make sure to set the following environment variables:
|
||||
|
||||
- `CLIENT_ID_GITLAB_LOGIN`: The **Client ID** of your GitLab application.
|
||||
- `CLIENT_SECRET_GITLAB_LOGIN`: The **Secret** of your GitLab application.
|
||||
- (optional) `URL_GITLAB_LOGIN`: The URL of your self-hosted instance of GitLab where the OAuth application is registered. If no URL is passed in, this will default to `https://gitlab.com`.
|
||||
- `JWT_PROVIDER_AUTH_SECRET`: A secret key used for signing and verifying JWT. This could be a randomly-generated 256-bit hex string.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
|
||||
Once added, restart your Infisical instance and log in with GitLab.
|
||||
- `CLIENT_ID_GITLAB_LOGIN`: The **Client ID** of your GitLab application.
|
||||
- `CLIENT_SECRET_GITLAB_LOGIN`: The **Secret** of your GitLab application.
|
||||
- (optional) `URL_GITLAB_LOGIN`: The URL of your self-hosted instance of GitLab where the OAuth application is registered. If no URL is passed in, this will default to `https://gitlab.com`.
|
||||
- `AUTH_SECRET`: A secret key used for signing and verifying JWT. This can be a random 32-byte base64 string generated with `openssl rand -base64 32`.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
|
||||
Once added, restart your Infisical instance and log in with GitLab.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## FAQ
|
||||
|
||||
@ -45,7 +46,7 @@ Once added, restart your Infisical instance and log in with GitLab.
|
||||
It is likely that you have misconfigured your self-hosted instance of Infisical. You should:
|
||||
|
||||
- Check that you have set the `CLIENT_ID_GITLAB_LOGIN`, `CLIENT_SECRET_GITLAB_LOGIN`,
|
||||
`JWT_PROVIDER_AUTH_SECRET`, and `SITE_URL` environment variables.
|
||||
`AUTH_SECRET`, and `SITE_URL` environment variables.
|
||||
- Check that the **Redirect URI** specified in GitLab matches the `SITE_URL` environment variable.
|
||||
For example, if the former is `https://app.infisical.com/api/v1/sso/gitlab` then the latter should be `https://app.infisical.com`.
|
||||
</Accordion>
|
||||
|
@ -5,31 +5,32 @@ description: "Configure Google SSO for Infisical"
|
||||
|
||||
Using Google SSO on a self-hosted instance of Infisical requires configuring an OAuth2 application in GCP and registering your instance with it.
|
||||
|
||||
## Create an OAuth2 application in GCP
|
||||
<Steps>
|
||||
<Step title="Create an OAuth2 application in GCP">
|
||||
Navigate to your project API & Services > Credentials to create a new OAuth2 application.
|
||||
|
||||

|
||||

|
||||
|
||||
Navigate to your project API & Services > Credentials to create a new OAuth2 application.
|
||||
|
||||

|
||||

|
||||
Create the application. As part of the form, add to **Authorized redirect URIs**: `https://your-domain.com/api/v1/sso/google`.
|
||||
|
||||
Create the application. As part of the form, add to **Authorized redirect URIs**: `https://your-domain.com/api/v1/sso/google`.
|
||||

|
||||
</Step>
|
||||
<Step title="Add your OAuth2 application credentials to Infisical">
|
||||
Obtain the **Client ID** and **Client Secret** for your GCP OAuth2 application.
|
||||
|
||||

|
||||

|
||||
|
||||
Back in your Infisical instance, make sure to set the following environment variables:
|
||||
|
||||
## Add your OAuth2 application credentials to Infisical
|
||||
|
||||
Obtain the **Client ID** and **Client Secret** for your GCP OAuth2 application.
|
||||
|
||||

|
||||
|
||||
Back in your Infisical instance, make sure to set the following environment variables:
|
||||
|
||||
- `CLIENT_ID_GOOGLE_LOGIN`: The **Client ID** of your GCP OAuth2 application.
|
||||
- `CLIENT_SECRET_GOOGLE_LOGIN`: The **Client Secret** of your GCP OAuth2 application.
|
||||
- `JWT_PROVIDER_AUTH_SECRET`: A secret key used for signing and verifying JWT. This could be a randomly-generated 256-bit hex string.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
|
||||
Once added, restart your Infisical instance and log in with Google
|
||||
- `CLIENT_ID_GOOGLE_LOGIN`: The **Client ID** of your GCP OAuth2 application.
|
||||
- `CLIENT_SECRET_GOOGLE_LOGIN`: The **Client Secret** of your GCP OAuth2 application.
|
||||
- `AUTH_SECRET`: A secret key used for signing and verifying JWT. This can be a random 32-byte base64 string generated with `openssl rand -base64 32`.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
|
||||
Once added, restart your Infisical instance and log in with Google
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## FAQ
|
||||
|
||||
@ -38,7 +39,7 @@ Once added, restart your Infisical instance and log in with Google
|
||||
It is likely that you have misconfigured your self-hosted instance of Infisical. You should:
|
||||
|
||||
- Check that you have set the `CLIENT_ID_GOOGLE_LOGIN`, `CLIENT_SECRET_GOOGLE_LOGIN`,
|
||||
`JWT_PROVIDER_AUTH_SECRET`, and `SITE_URL` environment variables.
|
||||
`AUTH_SECRET`, and `SITE_URL` environment variables.
|
||||
- Check that the **Authorized redirect URI** specified in GCP matches the `SITE_URL` environment variable.
|
||||
For example, if the former is `https://app.infisical.com/api/v1/sso/google` then the latter should be `https://app.infisical.com`.
|
||||
</Accordion>
|
||||
|
@ -10,73 +10,77 @@ description: "Configure JumpCloud SAML for Infisical SSO"
|
||||
then you should contact team@infisical.com to purchase an enterprise license to use it.
|
||||
</Info>
|
||||
|
||||
1. In Infisical, head over to your organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
Next, copy the **ACS URL** and **SP Entity ID** to use when configuring the JumpCloud SAML application.
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head over to your organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
|
||||

|
||||
Next, copy the **ACS URL** and **SP Entity ID** to use when configuring the JumpCloud SAML application.
|
||||
|
||||
2. In the JumpCloud Admin Portal, navigate to User Authentication > SSO and create an application. If this is your first application, select **Get Started**;
|
||||
if not, select **+Add New Application**
|
||||

|
||||
</Step>
|
||||
<Step title="Create a SAML application in JumpCloud">
|
||||
2.1. In the JumpCloud Admin Portal, navigate to User Authentication > SSO and create an application. If this is your first application, select **Get Started**; if not, select **+Add New Application**
|
||||
|
||||

|
||||

|
||||
|
||||
3. Next, select **Custom SAML App** to open up the **New SSO** dialog.
|
||||
2.2. Next, select **Custom SAML App** to open up the **New SSO** dialog.
|
||||
|
||||

|
||||

|
||||
|
||||
4. In the **General Info** tab, give the application a unique name like Infisical.
|
||||
2.3. In the **General Info** tab, give the application a unique name like Infisical.
|
||||
|
||||

|
||||

|
||||
|
||||
5. In the **SSO** tab, set the **SP Entity ID** and **ACS URL** from step 1; set the **IdP Entity ID** to the same value as the **SP Entity ID**.
|
||||
2.4. In the **SSO** tab, set the **SP Entity ID** and **ACS URL** from step 1; set the **IdP Entity ID** to the same value as the **SP Entity ID**.
|
||||
|
||||

|
||||

|
||||
|
||||
6. On the same tab, check the **Sign Assertion** checkbox and fill the **IDP URL** to something unique.
|
||||
Copy the **IDP URL** to use when finishing configuring the JumpCloud SAML in Infisical.
|
||||
2.5. On the same tab, check the **Sign Assertion** checkbox and fill the **IDP URL** to something unique.
|
||||
Copy the **IDP URL** to use when finishing configuring the JumpCloud SAML in Infisical.
|
||||
|
||||

|
||||

|
||||
|
||||
7. On the same tab, in the **Attributes** section, configure the following map:
|
||||
2.6. On the same tab, in the **Attributes** section, configure the following map:
|
||||
|
||||
- `email -> email`
|
||||
- `firstName -> firstname`
|
||||
- `lastName -> lastname`
|
||||
- `email -> email`
|
||||
- `firstName -> firstname`
|
||||
- `lastName -> lastname`
|
||||
|
||||

|
||||

|
||||
|
||||
Finally press activate to create the SAML application.
|
||||
Finally press activate to create the SAML application.
|
||||
|
||||
8. Next, select the newly created SAML application and select **Download certificate** under the **IDP Certificate Valid** dropdown
|
||||
2.7. Next, select the newly created SAML application and select **Download certificate** under the **IDP Certificate Valid** dropdown
|
||||
|
||||

|
||||

|
||||
</Step>
|
||||
<Step title="Finish configuring SAML in Infisical">
|
||||
Back in Infisical, set the **IDP URL** from step 2.5 and the **IdP Entity ID** from step 2.4. Also, paste the certificate from the previous step.
|
||||
|
||||
9. Back in Infisical, set the **IDP URL** from step 6 and the **IdP Entity ID** from step 5. Also, paste the certificate from the previous step.
|
||||

|
||||
|
||||

|
||||
<Note>
|
||||
When pasting the certificate into Infisical, you'll want to retain `-----BEGIN
|
||||
CERTIFICATE-----` and `-----END CERTIFICATE-----` at the first and last line
|
||||
of the text area respectively.
|
||||
</Note>
|
||||
</Step>
|
||||
<Step title="Assign users in JumpCloud to the application">
|
||||
Back in JumpCloud, navigate to the **User Groups** tab and assign users to the newly created application.
|
||||
|
||||
<Note>
|
||||
When pasting the certificate into Infisical, you'll want to retain `-----BEGIN
|
||||
CERTIFICATE-----` and `-----END CERTIFICATE-----` at the first and last line
|
||||
of the text area respectively.
|
||||
</Note>
|
||||

|
||||
</Step>
|
||||
<Step title="Enable SAML SSO in Infisical">
|
||||
Enabling SAML SSO enforces all members in your organization to only be able to log into Infisical via JumpCloud.
|
||||
|
||||
10. Assignments
|
||||
|
||||
Back in JumpCloud, navigate to the **User Groups** tab and assign users to the newly created application.
|
||||
|
||||

|
||||
|
||||
11. Return to Infisical and enable SAML SSO.
|
||||
|
||||
Enabling SAML SSO enforces all members in your organization to only be able to log into Infisical via JumpCloud.
|
||||
|
||||

|
||||

|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
If you're configuring SAML SSO on a self-hosted instance of Infisical, make sure to
|
||||
set the `JWT_PROVIDER_AUTH_SECRET` and `SITE_URL` environment variable for it to work:
|
||||
set the `AUTH_SECRET` and `SITE_URL` environment variable for it to work:
|
||||
|
||||
- `JWT_PROVIDER_AUTH_SECRET`: This is secret key used for signing and verifying JWT. This could be a randomly-generated 256-bit hex string.
|
||||
- `AUTH_SECRET`: A secret key used for signing and verifying JWT. This can be a random 32-byte base64 string generated with `openssl rand -base64 32`.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
</Note>
|
||||
|
@ -10,78 +10,80 @@ description: "Configure Okta SAML 2.0 for Infisical SSO"
|
||||
then you should contact team@infisical.com to purchase an enterprise license to use it.
|
||||
</Info>
|
||||
|
||||
1. In Infisical, head over to your organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
Next, copy the **Single sign-on URL** and **Audience URI (SP Entity ID)** to use when configuring the Okta SAML 2.0 application.
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head over to your organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
|
||||
Next, copy the **Single sign-on URL** and **Audience URI (SP Entity ID)** to use when configuring the Okta SAML 2.0 application.
|
||||

|
||||
</Step>
|
||||
<Step title="Create a SAML application in Okta">
|
||||
In the Okta Admin Portal, select Applications > Applications from the navigation. On the Applications screen, select the **Create App Integration**
|
||||
button.
|
||||
|
||||

|
||||

|
||||
|
||||
In the Create a New Application Integration dialog, select the **SAML 2.0** radio button:
|
||||
|
||||
2. In the Okta Admin Portal, select Applications > Applications from the
|
||||
navigation. On the Applications screen, select the **Create App Integration**
|
||||
button.
|
||||

|
||||
|
||||
On the General Settings screen, give the application a unique name like Infisical and select **Next**.
|
||||
|
||||

|
||||
|
||||
On the Configure SAML screen, set the **Single sign-on URL** and **Audience URI (SP Entity ID)** from step 1.
|
||||
|
||||

|
||||

|
||||
|
||||
<Note>
|
||||
If you're self-hosting Infisical, then you will want to replace
|
||||
`https://app.infisical.com` with your own domain.
|
||||
</Note>
|
||||
|
||||
Also on the Configure SAML screen, configure the **Attribute Statements** to map:
|
||||
|
||||
3. In the Create a New Application Integration dialog, select the **SAML 2.0** radio button:
|
||||
- `id -> user.id`,
|
||||
- `email -> user.email`,
|
||||
- `firstName -> user.firstName`
|
||||
- `lastName -> user.lastName`
|
||||
|
||||

|
||||

|
||||
|
||||
4. On the General Settings screen, give the application a unique name like Infisical and select **Next**.
|
||||
Once configured, select **Next** to proceed to the Feedback screen and select **Finish**.
|
||||
</Step>
|
||||
<Step title="Retrieve Identity Provider (IdP) Information from Okta">
|
||||
Once your application is created, select the **Sign On** tab for the app and select the **View Setup Instructions** button located on the right side of the screen:
|
||||
|
||||

|
||||

|
||||
|
||||
5. On the Configure SAML screen, set the **Single sign-on URL** and **Audience URI (SP Entity ID)** from step 1.
|
||||
Copy the **Identity Provider Single Sign-On URL**, the **Identity Provider Issuer**, and the **X.509 Certificate** to use when finishing configuring Okta SAML in Infisical.
|
||||
|
||||

|
||||

|
||||
</Step>
|
||||
<Step title="Finish configuring SAML in Infisical">
|
||||
Back in Infisical, set **Identity Provider Single Sign-On URL**, **Identity Provider Issuer**,
|
||||
and **Certificate** to **X.509 Certificate** from step 3. Once you've done that, press **Update** to complete the required configuration.
|
||||
|
||||
<Note>
|
||||
If you're self-hosting Infisical, then you will want to replace
|
||||
`https://app.infisical.com` with your own domain.
|
||||
</Note>
|
||||

|
||||
</Step>
|
||||
<Step title="Assign users in Okta to the application">
|
||||
Back in Okta, navigate to the **Assignments** tab and select **Assign**. You can assign access to the application on a user-by-user basis using the Assign to People option, or in-bulk using the Assign to Groups option.
|
||||
|
||||
6. Also on the Configure SAML screen, configure the **Attribute Statements** to map:
|
||||

|
||||
|
||||
- `id -> user.id`,
|
||||
- `email -> user.email`,
|
||||
- `firstName -> user.firstName`
|
||||
- `lastName -> user.lastName`
|
||||
At this point, you have configured everything you need within the context of the Okta Admin Portal.
|
||||
</Step>
|
||||
<Step title="Enable SAML SSO in Infisical">
|
||||
Enabling SAML SSO enforces all members in your organization to only be able to log into Infisical via Okta.
|
||||
|
||||

|
||||
|
||||
Once configured, select **Next** to proceed to the Feedback screen and select **Finish**.
|
||||
|
||||
7. Get IdP values
|
||||
|
||||
Once your application is created, select the **Sign On** tab for the app and select the **View Setup Instructions** button located on the right side of the screen:
|
||||
|
||||

|
||||
|
||||
Copy the **Identity Provider Single Sign-On URL**, the **Identity Provider Issuer**, and the **X.509 Certificate** to use when finishing configuring Okta SAML in Infisical.
|
||||
|
||||

|
||||
|
||||
Back in Infisical, set **Identity Provider Single Sign-On URL**, **Identity Provider Issuer**,
|
||||
and **Certificate** to **X.509 Certificate** from above. Once you've done that, press **Update** to complete the required configuration.
|
||||
|
||||

|
||||
|
||||
8. Finally, navigate to the **Assignments** tab and select **Assign**
|
||||
|
||||
You can assign access to the application on a user-by-user basis using the Assign to People option, or in-bulk using the Assign to Groups option.
|
||||
|
||||

|
||||
|
||||
At this point, you have configured everything you need within the context of the Okta Admin Portal.
|
||||
|
||||
9. Return to Infisical and enable SAML SSO.
|
||||
|
||||
Enabling SAML SSO enforces all members in your organization to only be able to log into Infisical via Okta.
|
||||
|
||||

|
||||

|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
If you're configuring SAML SSO on a self-hosted instance of Infisical, make sure to
|
||||
set the `JWT_PROVIDER_AUTH_SECRET` and `SITE_URL` environment variable for it to work:
|
||||
set the `AUTH_SECRET` and `SITE_URL` environment variable for it to work:
|
||||
|
||||
- `JWT_PROVIDER_AUTH_SECRET`: This is secret key used for signing and verifying JWT. This could be a randomly-generated 256-bit hex string.
|
||||
- `AUTH_SECRET`: A secret key used for signing and verifying JWT. This can be a random 32-byte base64 string generated with `openssl rand -base64 32`.
|
||||
- `SITE_URL`: The URL of your self-hosted instance of Infisical - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
|
||||
</Note>
|
BIN
docs/images/sdk-flow.png
Normal file
After ![]() (image error) Size: 881 KiB |
BIN
docs/images/self-hosting/deployment-options/aws-lightsail/awsl-container-service-overview.png
Normal file
After ![]() (image error) Size: 412 KiB |
BIN
docs/images/self-hosting/deployment-options/aws-lightsail/awsl-create-container-service-capacity.png
Normal file
After ![]() (image error) Size: 418 KiB |
BIN
docs/images/self-hosting/deployment-options/aws-lightsail/awsl-create-container-service-deployment.png
Normal file
After ![]() (image error) Size: 359 KiB |
BIN
docs/images/self-hosting/deployment-options/aws-lightsail/awsl-create-container-service-envars.png
Normal file
After ![]() (image error) Size: 334 KiB |
BIN
docs/images/self-hosting/deployment-options/aws-lightsail/awsl-create-container-service-public-endpoint.png
Normal file
After ![]() (image error) Size: 338 KiB |
BIN
docs/images/self-hosting/deployment-options/aws-lightsail/awsl-create-container-service-summary.png
Normal file
After ![]() (image error) Size: 399 KiB |
BIN
docs/images/self-hosting/deployment-options/aws-lightsail/awsl-create-container-service.png
Normal file
After ![]() (image error) Size: 353 KiB |
After ![]() (image error) Size: 402 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-app-service-configuration.png
Normal file
After ![]() (image error) Size: 514 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-app-service-deployment-complete.png
Normal file
After ![]() (image error) Size: 362 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-app-service-overview.png
Normal file
After ![]() (image error) Size: 486 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-create-app-service-basics.png
Normal file
After ![]() (image error) Size: 316 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-create-app-service-docker.png
Normal file
After ![]() (image error) Size: 235 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-create-app-service-review.png
Normal file
After ![]() (image error) Size: 270 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-create-app-service.png
Normal file
After ![]() (image error) Size: 224 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-app-services/aas-select-app-services.png
Normal file
After ![]() (image error) Size: 448 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-container-instance-overview.png
Normal file
After ![]() (image error) Size: 319 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-create-container-instance-advanced.png
Normal file
After ![]() (image error) Size: 258 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-create-container-instance-basics-1.png
Normal file
After ![]() (image error) Size: 302 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-create-container-instance-basics-2.png
Normal file
After ![]() (image error) Size: 290 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-create-container-instance-networking.png
Normal file
After ![]() (image error) Size: 265 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-create-container-instance-review.png
Normal file
After ![]() (image error) Size: 259 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-create-container-instance.png
Normal file
After ![]() (image error) Size: 208 KiB |
BIN
docs/images/self-hosting/deployment-options/azure-container-instances/aci-select-container-instances.png
Normal file
After ![]() (image error) Size: 428 KiB |
After ![]() (image error) Size: 568 KiB |
BIN
docs/images/self-hosting/deployment-options/gcp-cloud-run/gcp-cloud-run-create-project-2.png
Normal file
After ![]() (image error) Size: 232 KiB |
BIN
docs/images/self-hosting/deployment-options/gcp-cloud-run/gcp-cloud-run-create-project.png
Normal file
After ![]() (image error) Size: 293 KiB |
BIN
docs/images/self-hosting/deployment-options/gcp-cloud-run/gcp-cloud-run-create-service-docker-image.png
Normal file
After ![]() (image error) Size: 437 KiB |
BIN
docs/images/self-hosting/deployment-options/gcp-cloud-run/gcp-cloud-run-create-service-envars.png
Normal file
After ![]() (image error) Size: 394 KiB |
BIN
docs/images/self-hosting/deployment-options/gcp-cloud-run/gcp-cloud-run-create-service.png
Normal file
After ![]() (image error) Size: 295 KiB |
BIN
docs/images/self-hosting/deployment-options/gcp-cloud-run/gcp-cloud-run-select-cloud-run.png
Normal file
After ![]() (image error) Size: 406 KiB |
BIN
docs/images/self-hosting/deployment-options/gcp-cloud-run/gcp-cloud-run-service-details.png
Normal file
After ![]() (image error) Size: 294 KiB |
After ![]() (image error) Size: 209 KiB |
BIN
docs/images/self-hosting/deployment-options/railway/railway-deploy-template-infisical.png
Normal file
After ![]() (image error) Size: 191 KiB |
After ![]() (image error) Size: 233 KiB |
BIN
docs/images/self-hosting/deployment-options/railway/railway-infisical-architecture.png
Normal file
After ![]() (image error) Size: 233 KiB |
After ![]() (image error) Size: 350 KiB |
After ![]() (image error) Size: 222 KiB |
After ![]() (image error) Size: 198 KiB |
After ![]() (image error) Size: 226 KiB |
After ![]() (image error) Size: 187 KiB |
@ -5,6 +5,21 @@ description: "How to use Infisical for secret management in Ansible"
|
||||
|
||||
The documentation for using Infisical to manage secrets in Ansible is currently available [here](https://galaxy.ansible.com/ui/repo/published/infisical/vault/).
|
||||
|
||||
<Info>
|
||||
Have any questions? Join Infisical's [community Slack](https://infisical.com/slack) for quick support.
|
||||
</Info>
|
||||
|
||||
## Troubleshoot
|
||||
|
||||
<Accordion title="I'm getting a error related to objc[72832]: +[__NSCFConstantString initialize]">
|
||||
If you get this Python error when you running the lookup plugin:-
|
||||
|
||||
```
|
||||
objc[72832]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
|
||||
Fatal Python error: Aborted
|
||||
```
|
||||
|
||||
You will need to add this to your shell environment or ansible wrapper script:-
|
||||
|
||||
```
|
||||
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
|
@ -25,6 +25,6 @@ The Web UI is the browser-based portal that connects to the Infisical API.
|
||||
|
||||
Clients are any application or infrastructure that connecting to the Infisical API using one of the below methods:
|
||||
- Public API: Making API requests directly to the Infisical API.
|
||||
- Client SDK: A platform-specific library with method abstractions for working with secrets. Currently, there are two official SDKs: [Node SDK](https://github.com/Infisical/infisical-node) and [Python SDK](https://github.com/Infisical/infisical-python).
|
||||
- Client SDK: A platform-specific library with method abstractions for working with secrets. Currently, there are three official SDKs: [Node SDK](https://infisical.com/docs/sdks/languages/node), [Python SDK](https://infisical.com/docs/sdks/languages/python), and [Java SDK](https://infisical.com/docs/sdks/languages/java).
|
||||
- CLI: A terminal-based interface for interacting with the Infisical API.
|
||||
- Kubernetes Operator: This operator retrieves secrets from Infisical and securely store
|
@ -159,10 +159,16 @@
|
||||
"pages": [
|
||||
"self-hosting/overview",
|
||||
"self-hosting/deployment-options/standalone-infisical",
|
||||
"self-hosting/deployment-options/docker-compose",
|
||||
"self-hosting/deployment-options/kubernetes-helm",
|
||||
"self-hosting/deployment-options/aws-ec2",
|
||||
"self-hosting/deployment-options/docker-compose",
|
||||
"self-hosting/deployment-options/digital-ocean-marketplace"
|
||||
"self-hosting/deployment-options/aws-lightsail",
|
||||
"self-hosting/deployment-options/gcp-cloud-run",
|
||||
"self-hosting/deployment-options/azure-app-services",
|
||||
"self-hosting/deployment-options/azure-container-instances",
|
||||
"self-hosting/deployment-options/digital-ocean-marketplace",
|
||||
"self-hosting/deployment-options/fly.io",
|
||||
"self-hosting/deployment-options/railway"
|
||||
]
|
||||
},
|
||||
"self-hosting/configuration/envars",
|
||||
@ -442,13 +448,30 @@
|
||||
"pages": ["changelog/overview"]
|
||||
},
|
||||
{
|
||||
"group": "Contributing",
|
||||
"group": "",
|
||||
"pages": [
|
||||
"contributing/overview",
|
||||
"contributing/code-of-conduct",
|
||||
"contributing/developing",
|
||||
"contributing/pull-requests",
|
||||
"contributing/faq"
|
||||
{
|
||||
"group": "Getting Started",
|
||||
"pages": [
|
||||
"contributing/getting-started/overview",
|
||||
"contributing/getting-started/code-of-conduct",
|
||||
"contributing/getting-started/pull-requests",
|
||||
"contributing/getting-started/faq"
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Contributing to platform",
|
||||
"pages": [
|
||||
"contributing/platform/developing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Contributing to SDK",
|
||||
"pages": [
|
||||
"contributing/sdk/developing"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
391
docs/sdks/languages/csharp.mdx
Normal file
@ -0,0 +1,391 @@
|
||||
---
|
||||
title: "C#"
|
||||
icon: "C#"
|
||||
---
|
||||
|
||||
If you're working with C#, the official [Infisical C# SDK](https://github.com/Infisical/sdk/tree/main/languages/csharp) package is the easiest way to fetch and work with secrets for your application.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```cs
|
||||
using Infisical.Sdk;
|
||||
|
||||
namespace Example
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
var settings = new ClientSettings
|
||||
{
|
||||
ClientId = "CLIENT_ID",
|
||||
ClientSecret = "CLIENT_SECRET",
|
||||
// SiteUrl = "http://localhost:8080", <-- This line can be omitted if you're using Infisical Cloud.
|
||||
};
|
||||
var infisical = new InfisicalClient(settings);
|
||||
|
||||
var options = new GetSecretOptions
|
||||
{
|
||||
SecretName = "TEST",
|
||||
ProjectId = "PROJECT_ID",
|
||||
Environment = "dev",
|
||||
};
|
||||
var secret = infisical.GetSecret(options);
|
||||
|
||||
|
||||
Console.WriteLine($"The value of secret '{secret.SecretKey}', is: {secret.SecretValue}");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example demonstrates how to use the Infisical C# SDK in a C# application. The application retrieves a secret named `TEST` from the `dev` environment of the `PROJECT_ID` project.
|
||||
|
||||
<Warning>
|
||||
We do not recommend hardcoding your [Machine Identity Tokens](/platform/identities/overview). Setting it as an environment variable would be best.
|
||||
</Warning>
|
||||
|
||||
# Installation
|
||||
|
||||
Run `npm` to add `@infisical/sdk` to your project.
|
||||
|
||||
```console
|
||||
$ dotnet add package Infisical.Sdk
|
||||
```
|
||||
# Configuration
|
||||
|
||||
Import the SDK and create a client instance with your [Machine Identity](/platform/identities/universal-auth).
|
||||
|
||||
```cs
|
||||
using Infisical.Sdk;
|
||||
|
||||
namespace Example
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
var settings = new ClientSettings
|
||||
{
|
||||
ClientId = "CLIENT_ID",
|
||||
ClientSecret = "CLIENT_SECRET",
|
||||
};
|
||||
|
||||
var infisical = new InfisicalClient(settings); // <-- Your SDK instance!
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ClientSettings methods
|
||||
|
||||
<ParamField query="options" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="ClientId" type="string" optional>
|
||||
Your machine identity client ID.
|
||||
</ParamField>
|
||||
<ParamField query="ClientSecret" type="string" optional>
|
||||
Your machine identity client secret.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="AccessToken" type="string" optional>
|
||||
An access token obtained from the machine identity login endpoint.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="CacheTtl" type="number" default="300" optional>
|
||||
Time-to-live (in seconds) for refreshing cached secrets.
|
||||
If manually set to 0, caching will be disabled, this is not recommended.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="SiteUrl()" type="string" default="https://app.infisical.com" optional>
|
||||
Your self-hosted absolute site URL including the protocol (e.g. `https://app.infisical.com`)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
### Caching
|
||||
|
||||
To reduce the number of API requests, the SDK temporarily stores secrets it retrieves. By default, a secret remains cached for 5 minutes after it's first fetched. Each time it's fetched again, this 5-minute timer resets. You can adjust this caching duration by setting the "cacheTTL" option when creating the client.
|
||||
|
||||
## Working with Secrets
|
||||
|
||||
### client.ListSecrets(options)
|
||||
|
||||
```cs
|
||||
var options = new ListSecretsOptions
|
||||
{
|
||||
ProjectId = "PROJECT_ID",
|
||||
Environment = "dev",
|
||||
Path = "/foo/bar",
|
||||
AttachToProcessEnv = false,
|
||||
};
|
||||
|
||||
var secrets = infisical.ListSecrets(options);
|
||||
```
|
||||
|
||||
Retrieve all secrets within the Infisical project and environment that client is connected to
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="Environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="ProjectId" type="string">
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="Path" type="string" optional>
|
||||
The path from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="AttachToProcessEnv" type="boolean" default="false" optional>
|
||||
Whether or not to set the fetched secrets to the process environment. If true, you can access the secrets like so `System.getenv("SECRET_NAME")`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="IncludeImports" type="boolean" default="false" optional>
|
||||
Whether or not to include imported secrets from the current path. Read about [secret import](/documentation/platform/secret-reference)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
### client.GetSecret(options)
|
||||
|
||||
```cs
|
||||
var options = new GetSecretOptions
|
||||
{
|
||||
SecretName = "AAAA",
|
||||
ProjectId = "659c781eb2d4fe3e307b77bd",
|
||||
Environment = "dev",
|
||||
};
|
||||
var secret = infisical.GetSecret(options);
|
||||
```
|
||||
|
||||
Retrieve a secret from Infisical.
|
||||
|
||||
By default, `GetSecret()` fetches and returns a shared secret.
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="SecretName" type="string" required>
|
||||
The key of the secret to retrieve.
|
||||
</ParamField>
|
||||
<ParamField query="ProjectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="Environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="Path" type="string" optional>
|
||||
The path from where secret should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="Type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.CreateSecret(options)
|
||||
|
||||
```cs
|
||||
var options = new CreateSecretOptions {
|
||||
Environment = "dev",
|
||||
ProjectId = "PROJECT_ID",
|
||||
|
||||
SecretName = "NEW_SECRET",
|
||||
SecretValue = "NEW_SECRET_VALUE",
|
||||
SecretComment = "This is a new secret",
|
||||
};
|
||||
|
||||
var newSecret = infisical.CreateSecret(options);
|
||||
```
|
||||
|
||||
Create a new secret in Infisical.
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="SecretName" type="string" required>
|
||||
The key of the secret to create.
|
||||
</ParamField>
|
||||
<ParamField query="SecretValue" type="string" required>
|
||||
The value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="ProjectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="Environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="Path" type="string" optional>
|
||||
The path from where secret should be created.
|
||||
</ParamField>
|
||||
<ParamField query="Type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.UpdateSecret(options)
|
||||
|
||||
```cs
|
||||
var options = new UpdateSecretOptions {
|
||||
Environment = "dev",
|
||||
ProjectId = "PROJECT_ID",
|
||||
|
||||
SecretName = "SECRET_TO_UPDATE",
|
||||
SecretValue = "NEW VALUE"
|
||||
};
|
||||
|
||||
var updatedSecret = infisical.UpdateSecret(options);
|
||||
```
|
||||
|
||||
Update an existing secret in Infisical.
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="SecretName" type="string" required>
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="SecretValue" type="string" required>
|
||||
The new value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="ProjectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="Environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="Path" type="string" optional>
|
||||
The path from where secret should be updated.
|
||||
</ParamField>
|
||||
<ParamField query="Type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.DeleteSecret(options)
|
||||
|
||||
```cs
|
||||
var options = new DeleteSecretOptions
|
||||
{
|
||||
Environment = "dev",
|
||||
ProjectId = "PROJECT_ID",
|
||||
SecretName = "NEW_SECRET",
|
||||
};
|
||||
|
||||
var deletedSecret = infisical.DeleteSecret(options);
|
||||
```
|
||||
|
||||
Delete a secret in Infisical.
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="SecretName" type="string">
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="ProjectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="Environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="Path" type="string" optional>
|
||||
The path from where secret should be deleted.
|
||||
</ParamField>
|
||||
<ParamField query="Type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Cryptography
|
||||
|
||||
### Create a symmetric key
|
||||
|
||||
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
|
||||
|
||||
```cs
|
||||
var key = infisical.CreateSymmetricKey();
|
||||
```
|
||||
|
||||
#### Returns (string)
|
||||
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
|
||||
|
||||
### Encrypt symmetric
|
||||
```cs
|
||||
var options = new EncryptSymmetricOptions
|
||||
{
|
||||
Plaintext = "Infisical is awesome!",
|
||||
Key = key,
|
||||
};
|
||||
|
||||
var encryptedData = infisical.EncryptSymmetric(options);
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="Plaintext" type="string">
|
||||
The plaintext you want to encrypt.
|
||||
</ParamField>
|
||||
<ParamField query="Key" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (object)
|
||||
`Tag` (string): A base64-encoded, 128-bit authentication tag.
|
||||
`Iv` (string): A base64-encoded, 96-bit initialization vector.
|
||||
`CipherText` (string): A base64-encoded, encrypted ciphertext.
|
||||
|
||||
### Decrypt symmetric
|
||||
```cs
|
||||
var decryptOptions = new DecryptSymmetricOptions
|
||||
{
|
||||
Key = key,
|
||||
Ciphertext = encryptedData.Ciphertext,
|
||||
Iv = encryptedData.Iv,
|
||||
Tag = encryptedData.Tag,
|
||||
};
|
||||
|
||||
var decryptedPlaintext = infisical.DecryptSymmetric(decryptOptions);
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="Ciphertext" type="string">
|
||||
The ciphertext you want to decrypt.
|
||||
</ParamField>
|
||||
<ParamField query="Key" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
<ParamField query="Iv" type="string" required>
|
||||
The initialization vector to use for decryption.
|
||||
</ParamField>
|
||||
<ParamField query="Tag" type="string" required>
|
||||
The authentication tag to use for decryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (string)
|
||||
`Plaintext` (string): The decrypted plaintext.
|
||||
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
title: "Go"
|
||||
icon: "golang"
|
||||
---
|
||||
|
||||
Coming soon.
|
||||
|
||||
Follow this GitHub
|
||||
[issue](https://github.com/Infisical/infisical/issues/436) to stay updated.
|
@ -3,7 +3,380 @@ title: "Java"
|
||||
icon: "java"
|
||||
---
|
||||
|
||||
Coming soon.
|
||||
If you're working with Java, the official [Infisical Java SDK](https://github.com/Infisical/sdk/tree/main/languages/java) package is the easiest way to fetch and work with secrets for your application.
|
||||
|
||||
Follow this GitHub
|
||||
[issue](https://github.com/Infisical/infisical/issues/434) to stay updated.
|
||||
## Basic Usage
|
||||
|
||||
```java
|
||||
package com.example.app;
|
||||
|
||||
import com.infisical.sdk.InfisicalClient;
|
||||
import com.infisical.sdk.schema.*;
|
||||
|
||||
public class Example {
|
||||
public static void main(String[] args) {
|
||||
// Create a new Infisical Client
|
||||
ClientSettings settings = new ClientSettings();
|
||||
settings.setClientID("MACHINE_IDENTITY_CLIENT_ID");
|
||||
settings.setClientSecret("MACHINE_IDENTITY_CLIENT_SECRET");
|
||||
settings.setCacheTTL(Long.valueOf(300)); // 300 seconds, 5 minutes
|
||||
|
||||
InfisicalClient client = new InfisicalClient(settings);
|
||||
|
||||
// Create the options for fetching the secret
|
||||
GetSecretOptions options = new GetSecretOptions();
|
||||
options.setSecretName("TEST");
|
||||
options.setEnvironment("dev");
|
||||
options.setProjectID("PROJECT_ID");
|
||||
|
||||
// Fetch the sercret with the provided options
|
||||
GetSecretResponseSecret secret = client.getSecret(options);
|
||||
|
||||
// Print the value
|
||||
System.out.println(secret.getSecretValue());
|
||||
|
||||
// Important to avoid memory leaks!
|
||||
// If you intend to use the client throughout your entire application, you can omit this line.
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example demonstrates how to use the Infisical Java SDK in a Java application. The application retrieves a secret named `TEST` from the `dev` environment of the `PROJECT_ID` project.
|
||||
|
||||
<Warning>
|
||||
We do not recommend hardcoding your [Machine Identity Tokens](/platform/identities/overview). Setting it as an environment variable would be best.
|
||||
</Warning>
|
||||
|
||||
# Installation
|
||||
|
||||
The Infisical Java SDK is hosted on the GitHub Packages Apache Maven registry. Because of this you need to configure your environment properly so it's able to pull dependencies from the GitHub registry. Please check [this guide from GitHub](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry) on how to achieve this.
|
||||
|
||||
Our package is [located here](https://github.com/Infisical/sdk/packages/2019741). Please follow the installation guide on the page.
|
||||
|
||||
# Configuration
|
||||
|
||||
Import the SDK and create a client instance with your [Machine Identity](/platform/identities/universal-auth).
|
||||
|
||||
```java
|
||||
import com.infisical.sdk.InfisicalClient;
|
||||
import com.infisical.sdk.schema.*;
|
||||
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
|
||||
ClientSettings settings = new ClientSettings();
|
||||
settings.setClientID("MACHINE_IDENTITY_CLIENT_ID");
|
||||
settings.setClientSecret("MACHINE_IDENTITY_CLIENT_SECRET");
|
||||
|
||||
InfisicalClient client = new InfisicalClient(settings); // Your client!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ClientSettings methods
|
||||
|
||||
<ParamField query="options" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setClientID()" type="string" optional>
|
||||
Your machine identity client ID.
|
||||
</ParamField>
|
||||
<ParamField query="setClientSecret()" type="string" optional>
|
||||
Your machine identity client secret.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="setAccessToken()" type="string" optional>
|
||||
An access token obtained from the machine identity login endpoint.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="setCacheTTL()" type="number" default="300" optional>
|
||||
Time-to-live (in seconds) for refreshing cached secrets.
|
||||
If manually set to 0, caching will be disabled, this is not recommended.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="setSiteURL()" type="string" default="https://app.infisical.com" optional>
|
||||
Your self-hosted absolute site URL including the protocol (e.g. `https://app.infisical.com`)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
### Caching
|
||||
|
||||
To reduce the number of API requests, the SDK temporarily stores secrets it retrieves. By default, a secret remains cached for 5 minutes after it's first fetched. Each time it's fetched again, this 5-minute timer resets. You can adjust this caching duration by setting the "cacheTTL" option when creating the client.
|
||||
|
||||
## Working with Secrets
|
||||
|
||||
### client.listSecrets(options)
|
||||
|
||||
```java
|
||||
ListSecretsOptions options = new ListSecretsOptions();
|
||||
options.setEnvironment("dev");
|
||||
options.setProjectID("PROJECT_ID");
|
||||
options.setPath("/foo/bar");
|
||||
options.setIncludeImports(false);
|
||||
|
||||
SecretElement[] secrets = client.listSecrets(options);
|
||||
```
|
||||
|
||||
Retrieve all secrets within the Infisical project and environment that client is connected to
|
||||
|
||||
#### Methods
|
||||
|
||||
<ParamField query="Parameters" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setEnvironment()" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="setProjectID()" type="string">
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="setPath()" type="string" optional>
|
||||
The path from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="setAttachToProcessEnv()" type="boolean" default="false" optional>
|
||||
Whether or not to set the fetched secrets to the process environment. If true, you can access the secrets like so `System.getenv("SECRET_NAME")`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="setIncludeImports()" type="boolean" default="false" optional>
|
||||
Whether or not to include imported secrets from the current path. Read about [secret import](/documentation/platform/secret-reference)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
### client.getSecret(options)
|
||||
|
||||
```java
|
||||
GetSecretOptions options = new GetSecretOptions();
|
||||
options.setSecretName("TEST");
|
||||
options.setEnvironment("dev");
|
||||
options.setProjectID("PROJECT_ID");
|
||||
|
||||
GetSecretResponseSecret secret = client.getSecret(options);
|
||||
|
||||
String secretValue = secret.getSecretValue();
|
||||
```
|
||||
|
||||
Retrieve a secret from Infisical.
|
||||
|
||||
By default, `getSecret()` fetches and returns a shared secret.
|
||||
|
||||
#### Methods
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setSecretName()" type="string" required>
|
||||
The key of the secret to retrieve.
|
||||
</ParamField>
|
||||
<ParamField query="setProjectID()" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="setEnvironment()" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="setPath()" type="string" optional>
|
||||
The path from where secret should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="setType()" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.createSecret(options)
|
||||
|
||||
```java
|
||||
CreateSecretOptions createOptions = new CreateSecretOptions();
|
||||
createOptions.setSecretName("NEW_SECRET");
|
||||
createOptions.setEnvironment("dev");
|
||||
createOptions.setProjectID("PROJECT_ID");
|
||||
createOptions.setSecretValue("SOME SECRET VALUE");
|
||||
createOptions.setPath("/"); // Default
|
||||
createOptions.setType("shared"); // Default
|
||||
|
||||
CreateSecretResponseSecret newSecret = client.createSecret(createOptions);
|
||||
```
|
||||
|
||||
Create a new secret in Infisical.
|
||||
|
||||
#### Methods
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setSecretName()" type="string" required>
|
||||
The key of the secret to create.
|
||||
</ParamField>
|
||||
<ParamField query="setSecretValue()" type="string" required>
|
||||
The value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="setProjectID()" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="setEnvironment()" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="setPath()" type="string" optional>
|
||||
The path from where secret should be created.
|
||||
</ParamField>
|
||||
<ParamField query="setType()" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.updateSecret(options)
|
||||
|
||||
```java
|
||||
UpdateSecretOptions options = new UpdateSecretOptions();
|
||||
|
||||
options.setSecretName("SECRET_TO_UPDATE");
|
||||
options.setSecretValue("NEW SECRET VALUE");
|
||||
options.setEnvironment("dev");
|
||||
options.setProjectID("PROJECT_ID");
|
||||
options.setPath("/"); // Default
|
||||
options.setType("shared"); // Default
|
||||
|
||||
UpdateSecretResponseSecret updatedSecret = client.updateSecret(options);
|
||||
```
|
||||
|
||||
Update an existing secret in Infisical.
|
||||
|
||||
#### Methods
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setSecretName()" type="string" required>
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="setSecretValue()" type="string" required>
|
||||
The new value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="setProjectID()" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="setEnvironment()" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="setPath()" type="string" optional>
|
||||
The path from where secret should be updated.
|
||||
</ParamField>
|
||||
<ParamField query="setType()" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.deleteSecret(options)
|
||||
|
||||
```java
|
||||
DeleteSecretOptions options = new DeleteSecretOptions();
|
||||
|
||||
options.setSecretName("SECRET_TO_DELETE");
|
||||
options.setEnvironment("dev");
|
||||
options.setProjectID("PROJECT_ID");
|
||||
options.setPath("/"); // Default
|
||||
options.setType("shared"); // Default
|
||||
|
||||
DeleteSecretResponseSecret deletedSecret = client.deleteSecret(options);
|
||||
```
|
||||
|
||||
Delete a secret in Infisical.
|
||||
|
||||
#### Methods
|
||||
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setSecretName()" type="string">
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="setProjectID()" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="setEnvironment()" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="setPath()" type="string" optional>
|
||||
The path from where secret should be deleted.
|
||||
</ParamField>
|
||||
<ParamField query="setType()" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Cryptography
|
||||
|
||||
### Create a symmetric key
|
||||
|
||||
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
|
||||
|
||||
```java
|
||||
String key = client.createSymmetricKey();
|
||||
```
|
||||
|
||||
#### Returns (string)
|
||||
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
|
||||
|
||||
### Encrypt symmetric
|
||||
```java
|
||||
EncryptSymmetricOptions options = new EncryptSymmetricOptions();
|
||||
options.setKey(key);
|
||||
options.setPlaintext("Infisical is awesome!");
|
||||
|
||||
EncryptSymmetricResponse encryptedData = client.encryptSymmetric(options);
|
||||
```
|
||||
|
||||
#### Methods
|
||||
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setPlaintext()" type="string">
|
||||
The plaintext you want to encrypt.
|
||||
</ParamField>
|
||||
<ParamField query="setKey()" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (object)
|
||||
`tag (getTag())` (string): A base64-encoded, 128-bit authentication tag.
|
||||
`iv (getIv())` (string): A base64-encoded, 96-bit initialization vector.
|
||||
`ciphertext (getCipherText())` (string): A base64-encoded, encrypted ciphertext.
|
||||
|
||||
|
||||
### Decrypt symmetric
|
||||
```java
|
||||
DecryptSymmetricOptions decryptOptions = new DecryptSymmetricOptions();
|
||||
decryptOptions.setKey(key);
|
||||
decryptOptions.setCiphertext(encryptedData.getCiphertext());
|
||||
decryptOptions.setIv(encryptedData.getIv());
|
||||
decryptOptions.setTag(encryptedData.getTag());
|
||||
|
||||
String decryptedString = client.decryptSymmetric(decryptOptions);
|
||||
```
|
||||
|
||||
#### Methods
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="setCiphertext()" type="string">
|
||||
The ciphertext you want to decrypt.
|
||||
</ParamField>
|
||||
<ParamField query="setKey()" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
<ParamField query="setIv()" type="string" required>
|
||||
The initialization vector to use for decryption.
|
||||
</ParamField>
|
||||
<ParamField query="setTag()" type="string" required>
|
||||
The authentication tag to use for decryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (string)
|
||||
`Plaintext` (string): The decrypted plaintext.
|
@ -3,205 +3,385 @@ title: "Node"
|
||||
icon: "node"
|
||||
---
|
||||
|
||||
If you're working with Node.js, the official [infisical-node](https://github.com/Infisical/infisical-node) package is the easiest way to fetch and work with secrets for your application.
|
||||
If you're working with Node.js, the official [infisical-node](https://github.com/Infisical/sdk/tree/main/languages/node) package is the easiest way to fetch and work with secrets for your application.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```js
|
||||
import express from "express";
|
||||
import InfisicalClient from "infisical-node";
|
||||
|
||||
import { InfisicalClient, LogLevel } from "@infisical/sdk";
|
||||
|
||||
const app = express();
|
||||
|
||||
const PORT = 3000;
|
||||
|
||||
const client = new InfisicalClient({
|
||||
token: "YOUR_INFISICAL_TOKEN"
|
||||
clientId: "YOUR_CLIENT_ID",
|
||||
clientSecret: "YOUR_CLIENT_SECRET",
|
||||
logLevel: LogLevel.Error
|
||||
});
|
||||
|
||||
app.get("/", async (req, res) => {
|
||||
// access value
|
||||
const name = await client.getSecret("NAME");
|
||||
res.send(`Hello! My name is: ${name.secretValue}`);
|
||||
// access value
|
||||
|
||||
const name = await client.getSecret({
|
||||
environment: "dev",
|
||||
projectId: "PROJECT_ID",
|
||||
path: "/",
|
||||
type: "shared",
|
||||
secretName: "NAME"
|
||||
});
|
||||
|
||||
res.send(`Hello! My name is: ${name.secretValue}`);
|
||||
});
|
||||
|
||||
app.listen(PORT, async () => {
|
||||
console.log(`App listening on port ${PORT}`);
|
||||
// initialize client
|
||||
|
||||
console.log(`App listening on port ${port}`);
|
||||
});
|
||||
```
|
||||
|
||||
This example demonstrates how to use the Infisical Node SDK with an Express application. The application retrieves a secret named "NAME" and responds to requests with a greeting that includes the secret value.
|
||||
|
||||
<Warning>
|
||||
We do not recommend hardcoding your [Infisical
|
||||
Token](/documentation/platform/token). Setting it as an environment
|
||||
variable would be best.
|
||||
We do not recommend hardcoding your [Machine Identity Tokens](/documentation/platform/identities/overview). Setting it as an environment variable
|
||||
would be best.
|
||||
</Warning>
|
||||
|
||||
## Installation
|
||||
|
||||
Run `npm` to add `infisical-node` to your project.
|
||||
Run `npm` to add `@infisical/sdk` to your project.
|
||||
|
||||
```console
|
||||
$ npm install infisical-node --save
|
||||
$ npm install @infisical/sdk
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Import the SDK and create a client instance with your [Infisical Token](/documentation/platform/token).
|
||||
Import the SDK and create a client instance with your [Machine Identity](/documentation/platform/identities/overview).
|
||||
|
||||
<Tabs>
|
||||
<Tab title="ES6">
|
||||
```js
|
||||
import InfisicalClient from "infisical-node";
|
||||
|
||||
import { InfisicalClient, LogLevel } from "@infisical/sdk";
|
||||
|
||||
const client = new InfisicalClient({
|
||||
token: "your_infisical_token"
|
||||
clientId: "YOUR_CLIENT_ID",
|
||||
clientSecret: "YOUR_CLIENT_SECRET",
|
||||
logLevel: LogLevel.Error
|
||||
});
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="ES5">
|
||||
```js
|
||||
const InfisicalClient = require("infisical-node");
|
||||
|
||||
const client = new InfisicalClient({
|
||||
token: "your_infisical_token"
|
||||
});
|
||||
````
|
||||
</Tab>
|
||||
const { InfisicalClient, LogLevel } = require("@infisical/sdk");
|
||||
|
||||
const client = new InfisicalClient({
|
||||
clientId: "YOUR_CLIENT_ID",
|
||||
clientSecret: "YOUR_CLIENT_SECRET",
|
||||
logLevel: LogLevel.Error
|
||||
});
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="options" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="token" type="string" optional>
|
||||
An [Infisical Token](/documentation/platform/token) scoped to a project
|
||||
and environment
|
||||
</ParamField>
|
||||
<ParamField
|
||||
query="siteURL"
|
||||
type="string"
|
||||
default="https://app.infisical.com"
|
||||
optional
|
||||
>
|
||||
Your self-hosted absolute site URL including the protocol (e.g.
|
||||
`https://app.infisical.com`)
|
||||
</ParamField>
|
||||
<ParamField query="cacheTTL" type="number" default="300" optional>
|
||||
Time-to-live (in seconds) for refreshing cached secrets. Default: `300`.
|
||||
</ParamField>
|
||||
<ParamField query="debug" type="boolean" default="false" optional>
|
||||
Whether or not debug mode is on
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="clientId" type="string" optional>
|
||||
Your machine identity client ID.
|
||||
</ParamField>
|
||||
<ParamField query="clientSecret" type="string" optional>
|
||||
Your machine identity client secret.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="accessToken" type="string" optional>
|
||||
An access token obtained from the machine identity login endpoint.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="cacheTtl" type="number" default="300" optional>
|
||||
Time-to-live (in seconds) for refreshing cached secrets.
|
||||
If manually set to 0, caching will be disabled, this is not recommended.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="siteUrl" type="string" default="https://app.infisical.com" optional>
|
||||
Your self-hosted absolute site URL including the protocol (e.g. `https://app.infisical.com`)
|
||||
</ParamField>
|
||||
<ParamField query="logLevel" type="enum" default="Error" optional>
|
||||
The level of logs you wish to log The logs are derived from Rust, as we have written our base SDK in Rust.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
## Caching
|
||||
### Caching
|
||||
|
||||
The SDK caches every secret and updates it periodically based on the provided `cacheTTL`. For example, if `cacheTTL` of `300` is provided, then a secret will be refetched 5 minutes after the first fetch; if the fetch fails, the cached secret is returned.
|
||||
|
||||
<Tip>
|
||||
For optimal performance, we recommend creating a single instance of the Infisical client and exporting it to be used across your entire app to take advantage of caching benefits.
|
||||
</Tip>
|
||||
To reduce the number of API requests, the SDK temporarily stores secrets it retrieves. By default, a secret remains cached for 5 minutes after it's first fetched. Each time it's fetched again, this 5-minute timer resets. You can adjust this caching duration by setting the "cacheTtl" option when creating the client.
|
||||
|
||||
## Working with Secrets
|
||||
|
||||
### client.getAllSecrets()
|
||||
### client.listSecrets(options)
|
||||
|
||||
```js
|
||||
const secrets = await client.getAllSecrets();
|
||||
const secrets = await client.listSecrets({
|
||||
environment: "dev",
|
||||
projectId: "PROJECT_ID",
|
||||
path: "/foo/bar/",
|
||||
includeImports: false
|
||||
});
|
||||
```
|
||||
|
||||
Retrieve all secrets within the Infisical project and environment that client is connected to
|
||||
|
||||
### client.getSecret(secretName, options)
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="projectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="attachToProcessEnv" type="boolean" default="false" optional>
|
||||
Whether or not to set the fetched secrets to the process environment. If true, you can access the secrets like so `process.env["SECRET_NAME"]`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="includeImports" type="false" default="boolean" optional>
|
||||
Whether or not to include imported secrets from the current path. Read about [secret import](/documentation/platform/secret-reference)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
### client.getSecret(options)
|
||||
|
||||
```js
|
||||
const secret = await client.getSecret("API_KEY");
|
||||
const value = secret.secretValue; // get its value
|
||||
const secret = await client.getSecret({
|
||||
environment: "dev",
|
||||
projectId: "PROJECT_ID",
|
||||
secretName: "API_KEY",
|
||||
path: "/",
|
||||
type: "shared"
|
||||
});
|
||||
```
|
||||
|
||||
Retrieve a secret from Infisical.
|
||||
|
||||
By default, `getSecret()` fetches and returns a personal secret. If not found, it returns a shared secret, or tries to retrieve the value from `process.env`. If a secret is fetched, `getSecret()` caches it to reduce excessive calls and re-fetches periodically based on the `cacheTTL` option (default is `300` seconds) when initializing the client — for more information, see the caching section.
|
||||
By default, `getSecret()` fetches and returns a shared secret.
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The key of the secret to retrieve
|
||||
</ParamField>
|
||||
<ParamField query="options" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="type" type="string" default="personal" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal"
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The key of the secret to retrieve.
|
||||
</ParamField>
|
||||
<ParamField query="projectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.createSecret(secretName, secretValue, options)
|
||||
### client.createSecret(options)
|
||||
|
||||
```js
|
||||
const newApiKey = await client.createSecret("API_KEY", "FOO");
|
||||
const newApiKey = await client.createSecret({
|
||||
projectId: "PROJECT_ID",
|
||||
environment: "dev",
|
||||
secretName: "API_KEY",
|
||||
secretValue: "SECRET VALUE",
|
||||
path: "/",
|
||||
type: "shared"
|
||||
});
|
||||
```
|
||||
|
||||
Create a new secret in Infisical.
|
||||
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The key of the secret to create
|
||||
</ParamField>
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The value of the secret to create
|
||||
</ParamField>
|
||||
<ParamField query="options" type="object" default="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="type" type="string" default="shared" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". A personal secret can only be created if a shared secret with the same name exists.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The key of the secret to create.
|
||||
</ParamField>
|
||||
<ParamField query="secretValue" type="string" required>
|
||||
The value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="projectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be created.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.updateSecret(secretName, secretValue, options)
|
||||
### client.updateSecret(options)
|
||||
|
||||
```js
|
||||
const updatedApiKey = await client.updateSecret("API_KEY", "BAR");
|
||||
const updatedApiKey = await client.updateSecret({
|
||||
secretName: "API_KEY",
|
||||
secretValue: "NEW SECRET VALUE",
|
||||
projectId: "PROJECT_ID",
|
||||
environment: "dev",
|
||||
path: "/",
|
||||
type: "shared"
|
||||
});
|
||||
```
|
||||
|
||||
Update an existing secret in Infisical.
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The key of the secret to update
|
||||
</ParamField>
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The new value of the secret
|
||||
</ParamField>
|
||||
<ParamField query="options" type="object" default="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="type" type="string" default="shared" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal"
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="secretValue" type="string" required>
|
||||
The new value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="projectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be updated.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.deleteSecret(secretName, options)
|
||||
### client.deleteSecret(options)
|
||||
|
||||
```js
|
||||
const deletedSecret = await client.deleteSecret("API_KEY");
|
||||
const deletedSecret = await client.deleteSecret({
|
||||
secretName: "API_KEY",
|
||||
|
||||
environment: "dev",
|
||||
projectId: "PROJECT_ID",
|
||||
path: "/",
|
||||
|
||||
type: "shared"
|
||||
});
|
||||
```
|
||||
|
||||
Delete a secret in Infisical.
|
||||
|
||||
<ParamField query="secretName" type="string" required>
|
||||
The key of the secret to delete
|
||||
</ParamField>
|
||||
<ParamField query="options" type="object" default="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="type" type="string" default="shared" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". Note that deleting a shared secret also deletes all associated personal secrets.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secretName" type="string">
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="projectId" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be deleted.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Cryptography
|
||||
|
||||
### Create a symmetric key
|
||||
|
||||
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
|
||||
|
||||
```js
|
||||
const key = client.createSymmetricKey();
|
||||
```
|
||||
|
||||
#### Returns (string)
|
||||
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
|
||||
|
||||
### Encrypt symmetric
|
||||
```js
|
||||
const { iv, tag, ciphertext } = await client.encryptSymmetric({
|
||||
key: key,
|
||||
plaintext: "Infisical is awesome!",
|
||||
})
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="plaintext" type="string">
|
||||
The plaintext you want to encrypt.
|
||||
</ParamField>
|
||||
<ParamField query="key" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (object)
|
||||
`tag` (string): A base64-encoded, 128-bit authentication tag.
|
||||
`iv` (string): A base64-encoded, 96-bit initialization vector.
|
||||
`ciphertext` (string): A base64-encoded, encrypted ciphertext.
|
||||
|
||||
### Decrypt symmetric
|
||||
```js
|
||||
const decryptedString = await client.decryptSymmetric({
|
||||
key: key,
|
||||
iv: iv,
|
||||
tag: tag,
|
||||
ciphertext: ciphertext,
|
||||
});
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="ciphertext" type="string">
|
||||
The ciphertext you want to decrypt.
|
||||
</ParamField>
|
||||
<ParamField query="key" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
<ParamField query="iv" type="string" required>
|
||||
The initialization vector to use for decryption.
|
||||
</ParamField>
|
||||
<ParamField query="tag" type="string" required>
|
||||
The authentication tag to use for decryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (string)
|
||||
`plaintext` (string): The decrypted plaintext.
|
||||
|
@ -1,8 +0,0 @@
|
||||
---
|
||||
title: "PHP"
|
||||
icon: "php"
|
||||
---
|
||||
|
||||
Coming soon.
|
||||
|
||||
Follow this GitHub [issue](https://github.com/Infisical/infisical/issues/531) to stay updated.
|
@ -3,31 +3,38 @@ title: "Python"
|
||||
icon: "python"
|
||||
---
|
||||
|
||||
If you're working with Python, the official [infisical-python](https://github.com/Infisical/infisical-python) package is the easiest way to fetch and work with secrets for your application.
|
||||
If you're working with Python, the official [infisical-python](https://github.com/Infisical/sdk/edit/main/crates/infisical-py) package is the easiest way to fetch and work with secrets for your application.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```py
|
||||
from flask import Flask
|
||||
from infisical import InfisicalClient
|
||||
from infisical_client import ClientSettings, InfisicalClient, GetSecretOptions
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
client = InfisicalClient(token="your_infisical_token")
|
||||
client = InfisicalClient(ClientSettings(
|
||||
client_id="MACHINE_IDENTITY_CLIENT_ID",
|
||||
client_secret="MACHINE_IDENTITY_CLIENT_SECRET",
|
||||
))
|
||||
|
||||
@app.route("/")
|
||||
def hello_world():
|
||||
# access value
|
||||
name = client.get_secret("NAME")
|
||||
|
||||
name = client.getSecret(options=GetSecretOptions(
|
||||
environment="dev",
|
||||
project_id="PROJECT_ID",
|
||||
secret_name="NAME"
|
||||
))
|
||||
|
||||
return f"Hello! My name is: {name.secret_value}"
|
||||
```
|
||||
|
||||
This example demonstrates how to use the Infisical Python SDK with a Flask application. The application retrieves a secret named "NAME" and responds to requests with a greeting that includes the secret value.
|
||||
|
||||
<Warning>
|
||||
We do not recommend hardcoding your [Infisical
|
||||
Token](/documentation/platform/token). Setting it as an environment
|
||||
variable would be best.
|
||||
We do not recommend hardcoding your [Machine Identity Tokens](/platform/identities/overview). Setting it as an environment variable would be best.
|
||||
</Warning>
|
||||
|
||||
## Installation
|
||||
@ -35,135 +42,320 @@ This example demonstrates how to use the Infisical Python SDK with a Flask appli
|
||||
Run `pip` to add `infisical-python` to your project
|
||||
|
||||
```console
|
||||
$ pip install infisical
|
||||
$ pip install infisical-python
|
||||
```
|
||||
|
||||
Note: You need Python 3.7+.
|
||||
|
||||
## Configuration
|
||||
|
||||
Import the SDK and create a client instance with your [Infisical Token](/documentation/platform/token).
|
||||
Import the SDK and create a client instance with your [Machine Identity](/api-reference/overview/authentication).
|
||||
|
||||
```py
|
||||
from infisical import InfisicalClient
|
||||
from infisical_client import ClientSettings, InfisicalClient
|
||||
|
||||
client = InfisicalClient(token="your_infisical_token")
|
||||
client = InfisicalClient(ClientSettings(
|
||||
client_id="MACHINE_IDENTITY_CLIENT_ID",
|
||||
client_secret="MACHINE_IDENTITY_CLIENT_SECRET",
|
||||
))
|
||||
```
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="token" type="string" optional>
|
||||
An [Infisical Token](/documentation/platform/token) scoped to a project
|
||||
and environment
|
||||
</ParamField>
|
||||
<ParamField
|
||||
query="site_url"
|
||||
type="string"
|
||||
default="https://app.infisical.com"
|
||||
optional
|
||||
>
|
||||
Your self-hosted absolute site URL including the protocol (e.g.
|
||||
`https://app.infisical.com`)
|
||||
</ParamField>
|
||||
<ParamField query="cache_ttl" type="number" default="300" optional>
|
||||
Time-to-live (in seconds) for refreshing cached secrets. Default: `300`.
|
||||
</ParamField>
|
||||
<ParamField query="debug" type="boolean" default="false" optional>
|
||||
Whether or not debug mode is on
|
||||
</ParamField>
|
||||
<ParamField query="options" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="client_id" type="string" optional>
|
||||
Your Infisical Client ID.
|
||||
</ParamField>
|
||||
<ParamField query="client_secret" type="string" optional>
|
||||
Your Infisical Client Secret.
|
||||
</ParamField>
|
||||
<ParamField query="access_token" type="string" optional>
|
||||
If you want to directly pass an access token obtained from the authentication endpoints, you can do so.
|
||||
</ParamField>
|
||||
|
||||
## Caching
|
||||
<ParamField query="cache_ttl" type="number" default="300" optional>
|
||||
Time-to-live (in seconds) for refreshing cached secrets.
|
||||
If manually set to 0, caching will be disabled, this is not recommended.
|
||||
</ParamField>
|
||||
|
||||
The SDK caches every secret and updates it periodically based on the provided `cache_ttl`. For example, if `cache_ttl` of `300` is provided, then a secret will be refetched 5 minutes after the first fetch; if the fetch fails, the cached secret is returned.
|
||||
|
||||
<Tip>
|
||||
For optimal performance, we recommend creating a single instance of the Infisical client and exporting it to be used across your entire app to take advantage of caching benefits.
|
||||
</Tip>
|
||||
<ParamField
|
||||
query="site_url"
|
||||
type="string"
|
||||
default="https://app.infisical.com"
|
||||
optional
|
||||
>
|
||||
Your self-hosted absolute site URL including the protocol (e.g.
|
||||
`https://app.infisical.com`)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
### Caching
|
||||
|
||||
To reduce the number of API requests, the SDK temporarily stores secrets it retrieves. By default, a secret remains cached for 5 minutes after it's first fetched. Each time it's fetched again, this 5-minute timer resets. You can adjust this caching duration by setting the "cache_ttl" option when creating the client.
|
||||
|
||||
## Working with Secrets
|
||||
|
||||
### client.get_all_secrets()
|
||||
### client.listSecrets(options)
|
||||
|
||||
```py
|
||||
secrets = client.get_all_secrets()
|
||||
client.listSecrets(options=ListSecretsOptions(
|
||||
environment="dev",
|
||||
project_id="PROJECT_ID"
|
||||
))
|
||||
```
|
||||
|
||||
Retrieve all secrets within the Infisical project and environment that client is connected to
|
||||
|
||||
### client.get_secret(secret_name, options)
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object">
|
||||
<Expandable title="properties">
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="project_id" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="attach_to_process_env" type="boolean" default="false" optional>
|
||||
Whether or not to set the fetched secrets to the process environment. If true, you can access the secrets like so `process.env["SECRET_NAME"]`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="include_imports" type="boolean" default="false" optional>
|
||||
Whether or not to include imported secrets from the current path. Read about [secret import](/documentation/platform/secret-reference)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
|
||||
</ParamField>
|
||||
|
||||
### client.getSecret(options)
|
||||
|
||||
```py
|
||||
secret = client.get_secret("API_KEY")
|
||||
secret = client.getSecret(options=GetSecretOptions(
|
||||
environment="dev",
|
||||
project_id="PROJECT_ID",
|
||||
secret_name="API_KEY"
|
||||
))
|
||||
value = secret.secret_value # get its value
|
||||
```
|
||||
|
||||
By default, `get_secret()` fetches and returns a personal secret. If not found, it returns a shared secret, or tries to retrieve the value from `os.environ`. If a secret is fetched, `get_secret()` caches it to reduce excessive calls and re-fetches periodically based on the `cacheTTL` option (default is 300 seconds) when initializing the client — for more information, see the caching section.
|
||||
By default, `getSecret()` fetches and returns a shared secret. If not found, it returns a personal secret.
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="secret_name" type="string" required>
|
||||
The key of the secret to retrieve
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" default="personal" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal"
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secret_name" type="string" required>
|
||||
The key of the secret to retrieve
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="project_id" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "personal".
|
||||
</ParamField>
|
||||
<ParamField query="include_imports" type="boolean" default="false" optional>
|
||||
Whether or not to include imported secrets from the current path. Read about [secret import](/documentation/platform/secret-reference)
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.create_secret(secret_name, secret_value, options)
|
||||
### client.createSecret(options)
|
||||
|
||||
```py
|
||||
new_api_key = client.create_secret("API_KEY", "FOO");
|
||||
api_key = client.createSecret(options=CreateSecretOptions(
|
||||
secret_name="API_KEY",
|
||||
secret_value="Some API Key",
|
||||
environment="dev",
|
||||
project_id="PROJECT_ID"
|
||||
))
|
||||
```
|
||||
|
||||
Create a new secret in Infisical.
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="secret_name" type="string" required>
|
||||
The key of the secret to create
|
||||
</ParamField>
|
||||
<ParamField query="secret_value" type="string" required>
|
||||
The value of the secret to create
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" default="shared" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". A personal secret can only be created if a shared secret with the same name exists.
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secret_name" type="string" required>
|
||||
The key of the secret to create.
|
||||
</ParamField>
|
||||
<ParamField query="secret_value" type="string" required>
|
||||
The value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="project_id" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be created.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.update_secret(secret_name, secret_value, options)
|
||||
### client.updateSecret(options)
|
||||
|
||||
```py
|
||||
updated_api_key = client.update_secret("API_KEY", "BAR");
|
||||
client.updateSecret(options=UpdateSecretOptions(
|
||||
secret_name="API_KEY",
|
||||
secret_value="NEW_VALUE",
|
||||
environment="dev",
|
||||
project_id="PROJECT_ID"
|
||||
))
|
||||
```
|
||||
|
||||
Update an existing secret in Infisical.
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="secret_name" type="string" required>
|
||||
The key of the secret to update
|
||||
</ParamField>
|
||||
<ParamField query="secret_value" type="string" required>
|
||||
The new value of the secret
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" default="shared" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal"
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secret_name" type="string" required>
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="secret_value" type="string" required>
|
||||
The new value of the secret.
|
||||
</ParamField>
|
||||
<ParamField query="project_id" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be updated.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
### client.delete_secret(secret_name, options)
|
||||
### client.deleteSecret(options)
|
||||
|
||||
```py
|
||||
deleted_secret = client.delete_secret("API_KEY");
|
||||
client.deleteSecret(options=DeleteSecretOptions(
|
||||
environment="dev",
|
||||
project_id="PROJECT_ID",
|
||||
secret_name="API_KEY"
|
||||
))
|
||||
```
|
||||
|
||||
Delete a secret in Infisical.
|
||||
|
||||
### Parameters
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="secret_name" type="string" required>
|
||||
The key of the secret to delete
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" default="shared" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal"
|
||||
<ParamField query="Parameters" type="object" optional>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="secret_name" type="string">
|
||||
The key of the secret to update.
|
||||
</ParamField>
|
||||
<ParamField query="project_id" type="string" required>
|
||||
The project ID where the secret lives in.
|
||||
</ParamField>
|
||||
<ParamField query="environment" type="string" required>
|
||||
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
|
||||
</ParamField>
|
||||
<ParamField query="path" type="string" optional>
|
||||
The path from where secret should be deleted.
|
||||
</ParamField>
|
||||
<ParamField query="type" type="string" optional>
|
||||
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
Follow this GitHub
|
||||
[issue](https://github.com/Infisical/infisical/issues/433) to stay updated.
|
||||
## Cryptography
|
||||
|
||||
### Create a symmetric key
|
||||
|
||||
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
|
||||
|
||||
```py
|
||||
key = client.createSymmetricKey()
|
||||
```
|
||||
|
||||
#### Returns (string)
|
||||
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
|
||||
|
||||
### Encrypt symmetric
|
||||
```py
|
||||
encryptOptions = EncryptSymmetricOptions(
|
||||
key=key,
|
||||
plaintext="Infisical is awesome!"
|
||||
)
|
||||
|
||||
encryptedData = client.encryptSymmetric(encryptOptions)
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="plaintext" type="string">
|
||||
The plaintext you want to encrypt.
|
||||
</ParamField>
|
||||
<ParamField query="key" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (object)
|
||||
`tag` (string): A base64-encoded, 128-bit authentication tag.
|
||||
`iv` (string): A base64-encoded, 96-bit initialization vector.
|
||||
`ciphertext` (string): A base64-encoded, encrypted ciphertext.
|
||||
|
||||
### Decrypt symmetric
|
||||
```py
|
||||
decryptOptions = DecryptSymmetricOptions(
|
||||
ciphertext=encryptedData.ciphertext,
|
||||
iv=encryptedData.iv,
|
||||
tag=encryptedData.tag,
|
||||
key=key
|
||||
)
|
||||
|
||||
decryptedString = client.decryptSymmetric(decryptOptions)
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
<ParamField query="Parameters" type="object" required>
|
||||
<Expandable title="properties">
|
||||
<ParamField query="ciphertext" type="string">
|
||||
The ciphertext you want to decrypt.
|
||||
</ParamField>
|
||||
<ParamField query="key" type="string" required>
|
||||
The symmetric key to use for encryption.
|
||||
</ParamField>
|
||||
<ParamField query="iv" type="string" required>
|
||||
The initialization vector to use for decryption.
|
||||
</ParamField>
|
||||
<ParamField query="tag" type="string" required>
|
||||
The authentication tag to use for decryption.
|
||||
</ParamField>
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
#### Returns (string)
|
||||
`plaintext` (string): The decrypted plaintext.
|
||||
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
title: "Ruby"
|
||||
icon: "gem"
|
||||
---
|
||||
|
||||
Coming soon.
|
||||
|
||||
Follow this GitHub
|
||||
[issue](https://github.com/Infisical/infisical/issues/435) to stay updated.
|