Update docs for blind indices and secrets v3 endpoints

This commit is contained in:
Tuan Dang
2023-04-19 18:15:35 +03:00
parent ad5852fe3a
commit 9f944135b9
18 changed files with 1449 additions and 209 deletions
+653 -7
View File
@@ -1532,7 +1532,15 @@
"/api/v1/invite-org/signup": { "/api/v1/invite-org/signup": {
"post": { "post": {
"description": "", "description": "",
"parameters": [], "parameters": [
{
"name": "host",
"in": "header",
"schema": {
"type": "string"
}
}
],
"responses": { "responses": {
"200": { "200": {
"description": "OK" "description": "OK"
@@ -2071,6 +2079,15 @@
"targetEnvironment": { "targetEnvironment": {
"example": "any" "example": "any"
}, },
"targetEnvironmentId": {
"example": "any"
},
"targetService": {
"example": "any"
},
"targetServiceId": {
"example": "any"
},
"owner": { "owner": {
"example": "any" "example": "any"
}, },
@@ -2297,6 +2314,13 @@
"schema": { "schema": {
"type": "string" "type": "string"
} }
},
{
"name": "teamId",
"in": "query",
"schema": {
"type": "string"
}
} }
], ],
"responses": { "responses": {
@@ -2309,6 +2333,107 @@
} }
} }
}, },
"/api/v1/integration-auth/{integrationAuthId}/teams": {
"get": {
"description": "",
"parameters": [
{
"name": "integrationAuthId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v1/integration-auth/{integrationAuthId}/vercel/branches": {
"get": {
"description": "",
"parameters": [
{
"name": "integrationAuthId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "appId",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v1/integration-auth/{integrationAuthId}/railway/environments": {
"get": {
"description": "",
"parameters": [
{
"name": "integrationAuthId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "appId",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v1/integration-auth/{integrationAuthId}/railway/services": {
"get": {
"description": "",
"parameters": [
{
"name": "integrationAuthId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "appId",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v2/signup/complete-account/signup": { "/api/v2/signup/complete-account/signup": {
"post": { "post": {
"description": "", "description": "",
@@ -2870,9 +2995,6 @@
} }
} }
} }
},
"400": {
"description": "Bad Request"
} }
}, },
"security": [ "security": [
@@ -2882,6 +3004,26 @@
] ]
} }
}, },
"/api/v2/organizations/{organizationId}/service-accounts": {
"get": {
"description": "",
"parameters": [
{
"name": "organizationId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v2/workspace/{workspaceId}/environments": { "/api/v2/workspace/{workspaceId}/environments": {
"post": { "post": {
"description": "", "description": "",
@@ -4018,9 +4160,6 @@
"responses": { "responses": {
"200": { "200": {
"description": "OK" "description": "OK"
},
"400": {
"description": "Bad Request"
} }
}, },
"requestBody": { "requestBody": {
@@ -4073,6 +4212,138 @@
} }
} }
], ],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v2/service-accounts/me": {
"get": {
"description": "",
"parameters": [],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v2/service-accounts/{serviceAccountId}": {
"get": {
"description": "",
"parameters": [
{
"name": "serviceAccountId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
},
"delete": {
"description": "",
"parameters": [
{
"name": "serviceAccountId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v2/service-accounts/": {
"post": {
"description": "",
"parameters": [],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v2/service-accounts/{serviceAccountId}/name": {
"patch": {
"description": "",
"parameters": [
{
"name": "serviceAccountId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"example": "any"
}
}
}
}
}
}
}
},
"/api/v2/service-accounts/{serviceAccountId}/permissions/workspace": {
"get": {
"description": "",
"parameters": [
{
"name": "serviceAccountId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
},
"post": {
"description": "",
"parameters": [
{
"name": "serviceAccountId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": { "responses": {
"200": { "200": {
"description": "OK" "description": "OK"
@@ -4080,6 +4351,90 @@
"400": { "400": {
"description": "Bad Request" "description": "Bad Request"
} }
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"environment": {
"example": "any"
},
"workspaceId": {
"example": "any"
},
"read": {
"example": "any"
},
"write": {
"example": "any"
},
"encryptedKey": {
"example": "any"
},
"nonce": {
"example": "any"
}
}
}
}
}
}
}
},
"/api/v2/service-accounts/{serviceAccountId}/permissions/workspace/{serviceAccountWorkspacePermissionId}": {
"delete": {
"description": "",
"parameters": [
{
"name": "serviceAccountId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "serviceAccountWorkspacePermissionId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v2/service-accounts/{serviceAccountId}/keys": {
"get": {
"description": "",
"parameters": [
{
"name": "serviceAccountId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "workspaceId",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
} }
} }
}, },
@@ -4149,6 +4504,297 @@
} }
} }
}, },
"/api/v3/secrets/": {
"get": {
"description": "",
"parameters": [
{
"name": "workspaceId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "environment",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v3/secrets/{secretName}": {
"post": {
"description": "",
"parameters": [
{
"name": "secretName",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"example": "any"
},
"environment": {
"example": "any"
},
"type": {
"example": "any"
},
"secretKeyCiphertext": {
"example": "any"
},
"secretKeyIV": {
"example": "any"
},
"secretKeyTag": {
"example": "any"
},
"secretValueCiphertext": {
"example": "any"
},
"secretValueIV": {
"example": "any"
},
"secretValueTag": {
"example": "any"
},
"secretCommentCiphertext": {
"example": "any"
},
"secretCommentIV": {
"example": "any"
},
"secretCommentTag": {
"example": "any"
}
}
}
}
}
}
},
"get": {
"description": "",
"parameters": [
{
"name": "secretName",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "workspaceId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "environment",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "type",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
},
"patch": {
"description": "",
"parameters": [
{
"name": "secretName",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"example": "any"
},
"environment": {
"example": "any"
},
"type": {
"example": "any"
},
"secretValueCiphertext": {
"example": "any"
},
"secretValueIV": {
"example": "any"
},
"secretValueTag": {
"example": "any"
}
}
}
}
}
}
},
"delete": {
"description": "",
"parameters": [
{
"name": "secretName",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"example": "any"
},
"environment": {
"example": "any"
},
"type": {
"example": "any"
}
}
}
}
}
}
}
},
"/api/v3/workspaces/{workspaceId}/secrets/blind-index-status": {
"get": {
"description": "",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v3/workspaces/{workspaceId}/secrets": {
"get": {
"description": "",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v3/workspaces/{workspaceId}/secrets/names": {
"post": {
"description": "",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretsToUpdate": {
"example": "any"
}
}
}
}
}
}
}
},
"/api/status": { "/api/status": {
"get": { "get": {
"description": "", "description": "",
+1 -1
View File
@@ -220,7 +220,7 @@ const generateOpenAPISpec = async () => {
const outputJSONFile = '../spec.json'; const outputJSONFile = '../spec.json';
const outputYAMLFile = '../docs/spec.yaml'; const outputYAMLFile = '../docs/spec.yaml';
const endpointsFiles = ['../src/app.ts']; const endpointsFiles = ['../src/index.ts'];
const spec = await swaggerAutogen(outputJSONFile, endpointsFiles, doc); const spec = await swaggerAutogen(outputJSONFile, endpointsFiles, doc);
await fs.writeFile(outputYAMLFile, yaml.dump(spec.data)); await fs.writeFile(outputYAMLFile, yaml.dump(spec.data));
@@ -1,11 +1,11 @@
--- ---
title: "Create" title: "Create"
openapi: "POST /api/v2/secrets/" openapi: "POST /api/v3/secrets/{secretName}"
--- ---
<Tip> <Tip>
Using this route requires understanding Infisical's system and cryptography. Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the It may be helpful to read through the
[introduction](/api-reference/overview/introduction) and [guide for creating [introduction](/api-reference/overview/introduction) and [guide for creating
secrets](/api-reference/overview/examples/create-secrets). secrets](/api-reference/overview/examples/create-secret).
</Tip> </Tip>
@@ -1,4 +1,4 @@
--- ---
title: "Delete" title: "Delete"
openapi: "DELETE /api/v2/secrets/" openapi: "DELETE /api/v3/secrets/{secretName}"
--- ---
@@ -0,0 +1,11 @@
---
title: "Retrieve"
openapi: "GET /api/v3/secrets/{secretName}"
---
<Tip>
Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the
[introduction](/api-reference/overview/introduction) and [guide for retrieving
secrets](/api-reference/overview/examples/retrieve-secret).
</Tip>
@@ -1,11 +1,11 @@
--- ---
title: "Retrieve" title: "Retrieve All"
openapi: "GET /api/v2/secrets/" openapi: "GET /api/v3/secrets/"
--- ---
<Tip> <Tip>
Using this route requires understanding Infisical's system and cryptography. Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the It may be helpful to read through the
[introduction](/api-reference/overview/introduction) and [guide for retrieving [introduction](/api-reference/overview/introduction) and [guide for retrieving
secrets](/api-reference/overview/examples/retrieve-secrets). secrets](/api-reference/overview/examples/retrieve-secret).
</Tip> </Tip>
@@ -1,11 +1,11 @@
--- ---
title: "Update" title: "Update"
openapi: "PATCH /api/v2/secrets/" openapi: "PATCH /api/v3/secrets/{secretName}"
--- ---
<Tip> <Tip>
Using this route requires understanding Infisical's system and cryptography. Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the It may be helpful to read through the
[introduction](/api-reference/overview/introduction) and [guide for updating [introduction](/api-reference/overview/introduction) and [guide for updating
secrets](/api-reference/overview/examples/update-secrets). secrets](/api-reference/overview/examples/update-secret).
</Tip> </Tip>
@@ -0,0 +1,18 @@
---
title: "Blind Indices"
---
In April 2023, we added the capability for users to query for secrets by name to improve the user experience of Infisical. Previously, it was only possible to query by id of the secret or fetch all secrets belonging to a project and environment.
Blind indexing must be enabled for projects created prior to April 2023 to take effect. If your project can be blind indexed, then you'll see a section in your project settings appear as shown below:
![project enable blind indices](../../images/project-settings-blind-indices.png)
It works using virtually irreversible blind indices generated by applying `argon2id` to the name of each secret and a random 128-bit salt assigned to each project on the server. We continue to keep the values of secrets E2EE by default.
You can read more about it [here](/security/mechanics).
<Note>
As previously mentioned, all projects made after April 2023 are automatically blind indexed. If you created a project before this date, you have to enable it manually in your project settings.
</Note>
@@ -1,21 +1,21 @@
--- ---
title: "Create secrets" title: "Create secret"
description: "How to add a secret using an Infisical Token scoped to a project and environment"
--- ---
In this example, we demonstrate how to add secrets to a project and environment using an Infisical Token.
Prerequisites: Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com) - Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment. - Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment with write access enabled.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction). - Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).
## Flow ## Flow
1. [Get your Infisical Token data](/api-reference/endpoints/service-tokens/get) including a (encrypted) project key. 1. [Get your Infisical Token data](/api-reference/endpoints/service-tokens/get) including a (encrypted) project key.
2. Decrypt the (encrypted) project key with the key from your Infisical Token. 2. Decrypt the (encrypted) project key with the key from your Infisical Token.
3. Encrypt your secret(s) with the project key 3. Encrypt your secret with the project key
4. [Send (encrypted) secret(s) to Infical](/api-reference/endpoints/secrets/create) 4. [Send (encrypted) secret to Infisical](/api-reference/endpoints/secrets/create)
## Example ## Example
@@ -84,7 +84,7 @@ const createSecrets = async () => {
secret: serviceTokenSecret secret: serviceTokenSecret
}); });
// 3. Encrypt your secret(s) with the project key // 3. Encrypt your secret with the project key
const { const {
ciphertext: secretKeyCiphertext, ciphertext: secretKeyCiphertext,
iv: secretKeyIV, iv: secretKeyIV,
@@ -112,7 +112,12 @@ const createSecrets = async () => {
secret: projectKey secret: projectKey
}); });
const secret = { // 4. Send (encrypted) secret to Infisical
await axios.post(
`${BASE_URL}/api/v3/secrets/${secretKey}`,
{
workspaceId: serviceTokenData.workspace,
environment: serviceTokenData.environment,
type: secretType, type: secretType,
secretKeyCiphertext, secretKeyCiphertext,
secretKeyIV, secretKeyIV,
@@ -123,15 +128,6 @@ const createSecrets = async () => {
secretCommentCiphertext, secretCommentCiphertext,
secretCommentIV, secretCommentIV,
secretCommentTag secretCommentTag
}
// 4. Send (encrypted) secret(s) to Infisical
await axios.post(
`${BASE_URL}/api/v2/secrets`,
{
workspaceId: serviceTokenData.workspace,
environment: serviceTokenData.environment,
secrets: [secret]
}, },
{ {
headers: { headers: {
@@ -204,12 +200,17 @@ def create_secrets():
secret=service_token_secret, secret=service_token_secret,
) )
# 3. Encrypt your secret(s) with the project key # 3. Encrypt your secret with the project key
encrypted_key_data = encrypt(text=secret_key, secret=project_key) encrypted_key_data = encrypt(text=secret_key, secret=project_key)
encrypted_value_data = encrypt(text=secret_value, secret=project_key) encrypted_value_data = encrypt(text=secret_value, secret=project_key)
encrypted_comment_data = encrypt(text=secret_comment, secret=project_key) encrypted_comment_data = encrypt(text=secret_comment, secret=project_key)
secret = { # 4. Send (encrypted) secret to Infisical
requests.post(
f"{BASE_URL}/api/v3/secrets/{secret_key}",
json={
"workspaceId": service_token_data["workspace"],
"environment": service_token_data["environment"],
"type": secret_type, "type": secret_type,
"secretKeyCiphertext": encrypted_key_data["ciphertext"], "secretKeyCiphertext": encrypted_key_data["ciphertext"],
"secretKeyIV": encrypted_key_data["iv"], "secretKeyIV": encrypted_key_data["iv"],
@@ -219,16 +220,7 @@ def create_secrets():
"secretValueTag": encrypted_value_data["tag"], "secretValueTag": encrypted_value_data["tag"],
"secretCommentCiphertext": encrypted_comment_data["ciphertext"], "secretCommentCiphertext": encrypted_comment_data["ciphertext"],
"secretCommentIV": encrypted_comment_data["iv"], "secretCommentIV": encrypted_comment_data["iv"],
"secretCommentTag": encrypted_comment_data["tag"], "secretCommentTag": encrypted_comment_data["tag"]
}
# 4. Send (encrypted) secret (s) to Infisical
requests.post(
f"{BASE_URL}/api/v2/secrets",
json={
"workspaceId": service_token_data["workspace"],
"environment": service_token_data["environment"],
"secrets": [secret],
}, },
headers={"Authorization": f"Bearer {service_token}"}, headers={"Authorization": f"Bearer {service_token}"},
) )
@@ -239,9 +231,3 @@ create_secrets()
``` ```
</Tab> </Tab>
</Tabs> </Tabs>
<Info>
This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of
TweetNacl/Nacl, to perform asymmeric decryption of the project key but there
are ports of NaCl available in every major language.
</Info>
@@ -0,0 +1,94 @@
---
title: "Delete secret"
description: "How to delete a secret using an Infisical Token scoped to a project and environment"
---
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create either an [API Key](/api-reference/overview/authentication) or [Infisical Token](../../../getting-started/dashboard/token) for your project and environment with write access enabled.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).
## Example
<Tabs>
<Tab title="Javascript">
```js
const axios = require('axios');
const BASE_URL = 'https://app.infisical.com';
const deleteSecrets = async () => {
const serviceToken = 'your_service_token';
const secretType = 'shared' // 'shared' or 'personal'
const secretKey = 'some_key'
// 1. Get your Infisical Token data
const { data: serviceTokenData } = await axios.get(
`${BASE_URL}/api/v2/service-token`,
{
headers: {
Authorization: `Bearer ${serviceToken}`
}
}
);
// 2. Delete secret from Infisical
await axios.delete(
`${BASE_URL}/api/v3/secrets/${secretKey}`,
{
workspaceId: serviceTokenData.workspace,
environment: serviceTokenData.environment,
type: secretType
},
{
headers: {
Authorization: `Bearer ${serviceToken}`
},
}
);
};
deleteSecrets();
```
</Tab>
<Tab title="Python">
```Python
import requests
BASE_URL = "https://app.infisical.com"
def delete_secrets():
service_token = "<your_service_token>"
secret_type = "shared" # "shared" or "personal"
secret_key = "some_key"
# 1. Get your Infisical Token data
service_token_data = requests.get(
f"{BASE_URL}/api/v2/service-token",
headers={"Authorization": f"Bearer {service_token}"},
).json()
# 2. Delete secret from Infisical
requests.delete(
f"{BASE_URL}/api/v2/secrets/{secret_key}",
json={
"workspaceId": service_token_data["workspace"],
"environment": service_token_data["environment"],
"type": secret_type
},
headers={"Authorization": f"Bearer {service_token}"},
)
delete_secrets()
```
</Tab>
</Tabs>
<Info>
If using an `API_KEY` to authenticate with the Infisical API, then you should include it in the `X_API_KEY` header.
</Info>
@@ -1,70 +0,0 @@
---
title: "Delete secrets"
---
In this example, we demonstrate how to delete secrets
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
- Create either an [API Key](/api-reference/overview/authentication) or [Infisical Token](../../../getting-started/dashboard/token) for your project and environment.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
## Example
<Tabs>
<Tab title="Javascript">
```js
const axios = require('axios');
const BASE_URL = 'https://app.infisical.com';
const deleteSecrets = async () => {
const serviceToken = 'your_service_token';
const secretId = 'id_of_secret_to_delete';
// 6. Send ID(s) of secret(s) to delete to the Infisical API
await axios.delete(
`${BASE_URL}/api/v2/secrets`,
{
secretIds: [secretId],
},
{
headers: {
Authorization: `Bearer ${serviceToken}`
},
}
);
};
deleteSecrets();
```
</Tab>
<Tab title="Python">
```Python
import requests
BASE_URL = "https://app.infisical.com"
def delete_secrets():
service_token = "<your_service_token>"
secret_id = "id_of_secret_to_delete"
# Send ID(s) of secret(s) to delete to the Infisical API
requests.delete(
f"{BASE_URL}/api/v2/secrets",
json={"secretIds": [secret_id]},
headers={"Authorization": f"Bearer {service_token}"},
)
delete_secrets()
```
</Tab>
</Tabs>
<Info>
If using an `API_KEY` to authenticate with the Infisical API, then you should include it in the `X_API_KEY` header.
</Info>
@@ -0,0 +1,180 @@
---
title: "Retrieve secret"
description: "How to get a secret using an Infisical Token scoped to a project and environment"
---
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).
## Flow
1. [Get your Infisical Token data](/api-reference/endpoints/service-tokens/get) including a (encrypted) project key.
2. [Get the secret from your project and environment](/api-reference/endpoints/secrets/read-one).
3. Decrypt the (encrypted) project key with the key from your Infisical Token.
4. Decrypt the (encrypted) secret
## Example
<Tabs>
<Tab title="Javascript">
```js
const crypto = require('crypto');
const axios = require('axios');
const BASE_URL = 'https://app.infisical.com';
const ALGORITHM = 'aes-256-gcm';
const decrypt = ({ ciphertext, iv, tag, secret}) => {
const decipher = crypto.createDecipheriv(
ALGORITHM,
secret,
Buffer.from(iv, 'base64')
);
decipher.setAuthTag(Buffer.from(tag, 'base64'));
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
cleartext += decipher.final('utf8');
return cleartext;
}
const getSecret = async () => {
const serviceToken = 'your_service_token';
const serviceTokenSecret = serviceToken.substring(serviceToken.lastIndexOf('.') + 1);
const secretType = 'shared' // 'shared' or 'personal'
const secretKey = 'some_key';
// 1. Get your Infisical Token data
const { data: serviceTokenData } = await axios.get(
`${BASE_URL}/api/v2/service-token`,
{
headers: {
Authorization: `Bearer ${serviceToken}`
}
}
);
// 2. Get the secret from your project and environment
const { data } = await axios.get(
`${BASE_URL}/api/v3/secrets/${secretKey}?${new URLSearchParams({
environment: serviceTokenData.environment,
workspaceId: serviceTokenData.workspace,
type: secretType // optional, defaults to 'shared'
})}`,
{
headers: {
Authorization: `Bearer ${serviceToken}`
}
}
);
const encryptedSecret = data.secret;
// 3. Decrypt the (encrypted) project key with the key from your Infisical Token
const projectKey = decrypt({
ciphertext: serviceTokenData.encryptedKey,
iv: serviceTokenData.iv,
tag: serviceTokenData.tag,
secret: serviceTokenSecret
});
// 4. Decrypt the (encrypted) secret value
const secretValue = decrypt({
ciphertext: encryptedSecret.secretValueCiphertext,
iv: encryptedSecret.secretValueIV,
tag: encryptedSecret.secretValueTag,
secret: projectKey
});
console.log('secret: ', ({
secretKey,
secretValue
}));
}
getSecret();
```
</Tab>
<Tab title="Python">
```Python
import requests
import base64
from Cryptodome.Cipher import AES
BASE_URL = "http://app.infisical.com"
def decrypt(ciphertext, iv, tag, secret):
secret = bytes(secret, "utf-8")
iv = base64.standard_b64decode(iv)
tag = base64.standard_b64decode(tag)
ciphertext = base64.standard_b64decode(ciphertext)
cipher = AES.new(secret, AES.MODE_GCM, iv)
cipher.update(tag)
cleartext = cipher.decrypt(ciphertext).decode("utf-8")
return cleartext
def get_secret():
service_token = "your_service_token"
service_token_secret = service_token[service_token.rindex(".") + 1 :]
secret_type = "shared" # "shared" or "personal"
secret_key = "some_key"
# 1. Get your Infisical Token data
service_token_data = requests.get(
f"{BASE_URL}/api/v2/service-token",
headers={"Authorization": f"Bearer {service_token}"},
).json()
# 2. Get secret from your project and environment
data = requests.get(
f"{BASE_URL}/api/v3/secrets/{secret_key}",
params={
"environment": service_token_data["environment"],
"workspaceId": service_token_data["workspace"],
"type": secret_type # optional, defaults to "shared"
},
headers={"Authorization": f"Bearer {service_token}"},
).json()
encrypted_secret = data["secret"]
# 3. Decrypt the (encrypted) project key with the key from your Infisical Token
project_key = decrypt(
ciphertext=service_token_data["encryptedKey"],
iv=service_token_data["iv"],
tag=service_token_data["tag"],
secret=service_token_secret,
)
# 4. Decrypt the (encrypted) secret value
secret_value = decrypt(
ciphertext=encrypted_secret["secretValueCiphertext"],
iv=encrypted_secret["secretValueIV"],
tag=encrypted_secret["secretValueTag"],
secret=project_key,
)
print("secret: ", {
"secret_key": secret_key,
"secret_value": secret_value
})
get_secret()
```
</Tab>
</Tabs>
@@ -1,14 +1,14 @@
--- ---
title: "Retrieve secrets" title: "Retrieve secrets"
description: "How to get all secrets using an Infisical Token scoped to a project and environment"
--- ---
In this example, we demonstrate how to retrieve secrets from a project and environment using an Infisical Token.
Prerequisites: Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com). - Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment. - Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction). - Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).
## Flow ## Flow
@@ -58,7 +58,7 @@ const getSecrets = async () => {
// 2. Get secrets for your project and environment // 2. Get secrets for your project and environment
const { data } = await axios.get( const { data } = await axios.get(
`${BASE_URL}/api/v2/secrets?${new URLSearchParams({ `${BASE_URL}/api/v3/secrets?${new URLSearchParams({
environment: serviceTokenData.environment, environment: serviceTokenData.environment,
workspaceId: serviceTokenData.workspace workspaceId: serviceTokenData.workspace
})}`, })}`,
@@ -143,7 +143,7 @@ def get_secrets():
# 2. Get secrets for your project and environment # 2. Get secrets for your project and environment
data = requests.get( data = requests.get(
f"{BASE_URL}/api/v2/secrets", f"{BASE_URL}/api/v3/secrets",
params={ params={
"environment": service_token_data["environment"], "environment": service_token_data["environment"],
"workspaceId": service_token_data["workspace"], "workspaceId": service_token_data["workspace"],
@@ -193,9 +193,3 @@ get_secrets()
``` ```
</Tab> </Tab>
</Tabs> </Tabs>
<Info>
This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of
TweetNacl/Nacl, to perform asymmeric decryption of the project key but there
are ports of NaCl available in every major language.
</Info>
@@ -1,21 +1,21 @@
--- ---
title: "Update secrets" title: "Update secret"
description: "How to update a secret using an Infisical Token scoped to a project and environment"
--- ---
In this example, we demonstrate how to update secrets using an Infisical Token.
Prerequisites: Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com) - Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment. - Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment with write access enabled.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction). - Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).
## Flow ## Flow
1. [Get your Infisical Token data](/api-reference/endpoints/service-tokens/get) including a (encrypted) project key. 1. [Get your Infisical Token data](/api-reference/endpoints/service-tokens/get) including a (encrypted) project key.
2. Decrypt the (encrypted) project key with the key from your Infisical Token. 2. Decrypt the (encrypted) project key with the key from your Infisical Token.
3. Encrypt your updated secret(s) with the project key 3. Encrypt your updated secret with the project key
4. [Send (encrypted) updated secret(s) to Infical](/api-reference/endpoints/secrets/update) 4. [Send (encrypted) updated secret to Infical](/api-reference/endpoints/secrets/update)
## Example ## Example
@@ -60,7 +60,7 @@ const updateSecrets = async () => {
const serviceToken = 'your_service_token'; const serviceToken = 'your_service_token';
const serviceTokenSecret = serviceToken.substring(serviceToken.lastIndexOf('.') + 1); const serviceTokenSecret = serviceToken.substring(serviceToken.lastIndexOf('.') + 1);
const secretId = 'id_of_secret_to_update'; const secretType = 'shared' // 'shared' or 'personal'
const secretKey = 'some_key'; const secretKey = 'some_key';
const secretValue = 'updated_value'; const secretValue = 'updated_value';
const secretComment = 'updated_comment'; const secretComment = 'updated_comment';
@@ -83,7 +83,7 @@ const updateSecrets = async () => {
secret: serviceTokenSecret secret: serviceTokenSecret
}); });
// 3. Encrypt your updated secret(s) with the project key // 3. Encrypt your updated secret with the project key
const { const {
ciphertext: secretKeyCiphertext, ciphertext: secretKeyCiphertext,
iv: secretKeyIV, iv: secretKeyIV,
@@ -111,26 +111,19 @@ const updateSecrets = async () => {
secret: projectKey secret: projectKey
}); });
const secret = { // 4. Send (encrypted) updated secret to Infisical
id: secretId, await axios.patch(
workspace: serviceTokenData.workspace, `${BASE_URL}/api/v3/secrets/${secretKey}`,
{
workspaceId: serviceTokenData.workspace,
environment: serviceTokenData.environment, environment: serviceTokenData.environment,
secretKeyCiphertext, type: secretType,
secretKeyIV,
secretKeyTag,
secretValueCiphertext, secretValueCiphertext,
secretValueIV, secretValueIV,
secretValueTag, secretValueTag,
secretCommentCiphertext, secretCommentCiphertext,
secretCommentIV, secretCommentIV,
secretCommentTag secretCommentTag
}
// 4. Send (encrypted) updated secret(s) to Infisical
await axios.patch(
`${BASE_URL}/api/v2/secrets`,
{
secrets: [secret]
}, },
{ {
headers: { headers: {
@@ -184,7 +177,7 @@ def update_secret():
service_token = "your_service_token" service_token = "your_service_token"
service_token_secret = service_token[service_token.rindex(".") + 1 :] service_token_secret = service_token[service_token.rindex(".") + 1 :]
secret_id = "id_of_secret_to_update" secret_type = "shared" # "shared" or "personal"
secret_key = "some_key" secret_key = "some_key"
secret_value = "updated_value" secret_value = "updated_value"
secret_comment = "updated_comment" secret_comment = "updated_comment"
@@ -203,15 +196,18 @@ def update_secret():
secret=service_token_secret, secret=service_token_secret,
) )
# 3. Encrypt your updated secret(s) with the project key # 3. Encrypt your updated secret with the project key
encrypted_key_data = encrypt(text=secret_key, secret=project_key) encrypted_key_data = encrypt(text=secret_key, secret=project_key)
encrypted_value_data = encrypt(text=secret_value, secret=project_key) encrypted_value_data = encrypt(text=secret_value, secret=project_key)
encrypted_comment_data = encrypt(text=secret_comment, secret=project_key) encrypted_comment_data = encrypt(text=secret_comment, secret=project_key)
secret = { # 4. Send (encrypted) updated secret to Infisical
"id": secret_id, requests.patch(
"workspace": service_token_data["workspace"], f"{BASE_URL}/api/v3/secrets/{secret_key}",
json={
"workspaceId": service_token_data["workspace"],
"environment": service_token_data["environment"], "environment": service_token_data["environment"],
"type": secret_type,
"secretKeyCiphertext": encrypted_key_data["ciphertext"], "secretKeyCiphertext": encrypted_key_data["ciphertext"],
"secretKeyIV": encrypted_key_data["iv"], "secretKeyIV": encrypted_key_data["iv"],
"secretKeyTag": encrypted_key_data["tag"], "secretKeyTag": encrypted_key_data["tag"],
@@ -220,13 +216,8 @@ def update_secret():
"secretValueTag": encrypted_value_data["tag"], "secretValueTag": encrypted_value_data["tag"],
"secretCommentCiphertext": encrypted_comment_data["ciphertext"], "secretCommentCiphertext": encrypted_comment_data["ciphertext"],
"secretCommentIV": encrypted_comment_data["iv"], "secretCommentIV": encrypted_comment_data["iv"],
"secretCommentTag": encrypted_comment_data["tag"], "secretCommentTag": encrypted_comment_data["tag"]
} },
# 4. Send (encrypted) updated secret(s) to Infisical
requests.patch(
f"{BASE_URL}/api/v2/secrets",
json={"secrets": [secret]},
headers={"Authorization": f"Bearer {service_token}"}, headers={"Authorization": f"Bearer {service_token}"},
) )
@@ -236,9 +227,3 @@ update_secret()
``` ```
</Tab> </Tab>
</Tabs> </Tabs>
<Info>
This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of
TweetNacl/Nacl, to perform asymmeric decryption of the project key but there
are ports of NaCl available in every major language.
</Info>
+5 -1
View File
@@ -14,9 +14,13 @@ With the Public API, users can create, read, update, and delete secrets, as well
If you decide to make your own requests using the API reference instead, be prepared for a steeper learning curve and more manual work. If you decide to make your own requests using the API reference instead, be prepared for a steeper learning curve and more manual work.
</Warning> </Warning>
<Warning>
In April 2023, we added the capability for users to query for secrets by name to improve the user experience of Infisical. If your project was created prior to April 2023, please read and follow the section on [blind indices](./blind-indices) and how to enable them for better usage of Infisical.
</Warning>
## Concepts ## Concepts
Using Infisical's API to manage secrets requires a basic understanding of the system and its underlying cryptography detailed [here](/security/overview). Using Infisical's API to manage secrets requires a basic understanding of the system and its underlying cryptography detailed [here](/security/overview). A few key points:
- Each user has a public/private key pair that is stored with the platform; private keys are encrypted locally by protected keys that are encrypted by keys derived from Argon2id applied to the user's password before being sent off to the server during the account signup process. - Each user has a public/private key pair that is stored with the platform; private keys are encrypted locally by protected keys that are encrypted by keys derived from Argon2id applied to the user's password before being sent off to the server during the account signup process.
- Each (encrypted) secret belongs to a project and environment. - Each (encrypted) secret belongs to a project and environment.
Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB

+7 -4
View File
@@ -205,13 +205,15 @@
"pages": [ "pages": [
"api-reference/overview/introduction", "api-reference/overview/introduction",
"api-reference/overview/authentication", "api-reference/overview/authentication",
"api-reference/overview/blind-indices",
{ {
"group": "Examples", "group": "Examples",
"pages": [ "pages": [
"api-reference/overview/examples/create-secrets",
"api-reference/overview/examples/retrieve-secrets", "api-reference/overview/examples/retrieve-secrets",
"api-reference/overview/examples/update-secrets", "api-reference/overview/examples/create-secret",
"api-reference/overview/examples/delete-secrets" "api-reference/overview/examples/retrieve-secret",
"api-reference/overview/examples/update-secret",
"api-reference/overview/examples/delete-secret"
] ]
} }
] ]
@@ -250,8 +252,9 @@
{ {
"group": "Secrets", "group": "Secrets",
"pages": [ "pages": [
"api-reference/endpoints/secrets/create",
"api-reference/endpoints/secrets/read", "api-reference/endpoints/secrets/read",
"api-reference/endpoints/secrets/create",
"api-reference/endpoints/secrets/read-one",
"api-reference/endpoints/secrets/update", "api-reference/endpoints/secrets/update",
"api-reference/endpoints/secrets/delete", "api-reference/endpoints/secrets/delete",
"api-reference/endpoints/secrets/versions", "api-reference/endpoints/secrets/versions",
+394 -5
View File
@@ -940,7 +940,11 @@ paths:
/api/v1/invite-org/signup: /api/v1/invite-org/signup:
post: post:
description: '' description: ''
parameters: [] parameters:
- name: host
in: header
schema:
type: string
responses: responses:
'200': '200':
description: OK description: OK
@@ -1277,6 +1281,12 @@ paths:
example: any example: any
targetEnvironment: targetEnvironment:
example: any example: any
targetEnvironmentId:
example: any
targetService:
example: any
targetServiceId:
example: any
owner: owner:
example: any example: any
path: path:
@@ -1415,11 +1425,75 @@ paths:
required: true required: true
schema: schema:
type: string type: string
- name: teamId
in: query
schema:
type: string
responses: responses:
'200': '200':
description: OK description: OK
'400': '400':
description: Bad Request description: Bad Request
/api/v1/integration-auth/{integrationAuthId}/teams:
get:
description: ''
parameters:
- name: integrationAuthId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
/api/v1/integration-auth/{integrationAuthId}/vercel/branches:
get:
description: ''
parameters:
- name: integrationAuthId
in: path
required: true
schema:
type: string
- name: appId
in: query
schema:
type: string
responses:
'200':
description: OK
/api/v1/integration-auth/{integrationAuthId}/railway/environments:
get:
description: ''
parameters:
- name: integrationAuthId
in: path
required: true
schema:
type: string
- name: appId
in: query
schema:
type: string
responses:
'200':
description: OK
/api/v1/integration-auth/{integrationAuthId}/railway/services:
get:
description: ''
parameters:
- name: integrationAuthId
in: path
required: true
schema:
type: string
- name: appId
in: query
schema:
type: string
responses:
'200':
description: OK
/api/v2/signup/complete-account/signup: /api/v2/signup/complete-account/signup:
post: post:
description: '' description: ''
@@ -1771,10 +1845,20 @@ paths:
items: items:
$ref: '#/components/schemas/Project' $ref: '#/components/schemas/Project'
description: Projects of organization description: Projects of organization
'400':
description: Bad Request
security: security:
- apiKeyAuth: [] - apiKeyAuth: []
/api/v2/organizations/{organizationId}/service-accounts:
get:
description: ''
parameters:
- name: organizationId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
/api/v2/workspace/{workspaceId}/environments: /api/v2/workspace/{workspaceId}/environments:
post: post:
description: '' description: ''
@@ -2467,8 +2551,6 @@ paths:
responses: responses:
'200': '200':
description: OK description: OK
'400':
description: Bad Request
requestBody: requestBody:
content: content:
application/json: application/json:
@@ -2503,8 +2585,139 @@ paths:
responses: responses:
'200': '200':
description: OK description: OK
/api/v2/service-accounts/me:
get:
description: ''
parameters: []
responses:
'200':
description: OK
/api/v2/service-accounts/{serviceAccountId}:
get:
description: ''
parameters:
- name: serviceAccountId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
delete:
description: ''
parameters:
- name: serviceAccountId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
/api/v2/service-accounts/:
post:
description: ''
parameters: []
responses:
'200':
description: OK
/api/v2/service-accounts/{serviceAccountId}/name:
patch:
description: ''
parameters:
- name: serviceAccountId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
example: any
/api/v2/service-accounts/{serviceAccountId}/permissions/workspace:
get:
description: ''
parameters:
- name: serviceAccountId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
post:
description: ''
parameters:
- name: serviceAccountId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
'400': '400':
description: Bad Request description: Bad Request
requestBody:
content:
application/json:
schema:
type: object
properties:
environment:
example: any
workspaceId:
example: any
read:
example: any
write:
example: any
encryptedKey:
example: any
nonce:
example: any
/api/v2/service-accounts/{serviceAccountId}/permissions/workspace/{serviceAccountWorkspacePermissionId}:
delete:
description: ''
parameters:
- name: serviceAccountId
in: path
required: true
schema:
type: string
- name: serviceAccountWorkspacePermissionId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
/api/v2/service-accounts/{serviceAccountId}/keys:
get:
description: ''
parameters:
- name: serviceAccountId
in: path
required: true
schema:
type: string
- name: workspaceId
in: query
schema:
type: string
responses:
'200':
description: OK
/api/v2/api-key/: /api/v2/api-key/:
get: get:
description: '' description: ''
@@ -2546,6 +2759,182 @@ paths:
description: OK description: OK
'400': '400':
description: Bad Request description: Bad Request
/api/v3/secrets/:
get:
description: ''
parameters:
- name: workspaceId
in: query
schema:
type: string
- name: environment
in: query
schema:
type: string
responses:
'200':
description: OK
/api/v3/secrets/{secretName}:
post:
description: ''
parameters:
- name: secretName
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
requestBody:
content:
application/json:
schema:
type: object
properties:
workspaceId:
example: any
environment:
example: any
type:
example: any
secretKeyCiphertext:
example: any
secretKeyIV:
example: any
secretKeyTag:
example: any
secretValueCiphertext:
example: any
secretValueIV:
example: any
secretValueTag:
example: any
secretCommentCiphertext:
example: any
secretCommentIV:
example: any
secretCommentTag:
example: any
get:
description: ''
parameters:
- name: secretName
in: path
required: true
schema:
type: string
- name: workspaceId
in: query
schema:
type: string
- name: environment
in: query
schema:
type: string
- name: type
in: query
schema:
type: string
responses:
'200':
description: OK
patch:
description: ''
parameters:
- name: secretName
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
requestBody:
content:
application/json:
schema:
type: object
properties:
workspaceId:
example: any
environment:
example: any
type:
example: any
secretValueCiphertext:
example: any
secretValueIV:
example: any
secretValueTag:
example: any
delete:
description: ''
parameters:
- name: secretName
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
requestBody:
content:
application/json:
schema:
type: object
properties:
workspaceId:
example: any
environment:
example: any
type:
example: any
/api/v3/workspaces/{workspaceId}/secrets/blind-index-status:
get:
description: ''
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
/api/v3/workspaces/{workspaceId}/secrets:
get:
description: ''
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
/api/v3/workspaces/{workspaceId}/secrets/names:
post:
description: ''
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
requestBody:
content:
application/json:
schema:
type: object
properties:
secretsToUpdate:
example: any
/api/status: /api/status:
get: get:
description: '' description: ''