mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 21:27:31 +00:00
Improve API docs for non-E2EE
This commit is contained in:
@@ -23,7 +23,6 @@ import {
|
|||||||
router.get(
|
router.get(
|
||||||
"/raw",
|
"/raw",
|
||||||
query("workspaceId").exists().isString().trim(),
|
query("workspaceId").exists().isString().trim(),
|
||||||
query("workspaceId").exists().isString().trim(),
|
|
||||||
query("environment").exists().isString().trim(),
|
query("environment").exists().isString().trim(),
|
||||||
query("secretPath").default("/").isString().trim(),
|
query("secretPath").default("/").isString().trim(),
|
||||||
validateRequest,
|
validateRequest,
|
||||||
|
|||||||
@@ -3,15 +3,22 @@ title: "Authentication"
|
|||||||
description: "How to authenticate with the Infisical Public API"
|
description: "How to authenticate with the Infisical Public API"
|
||||||
---
|
---
|
||||||
|
|
||||||
## Essentials
|
The Public API accepts multiple modes of authentication being via [Infisical Token](/documentation/platform/token) or API Key.
|
||||||
|
|
||||||
The Public API accepts multiple modes of authentication being via API Key or [Infisical Token](/documentation/platform/token).
|
|
||||||
|
|
||||||
- API Key: Provides full access to all endpoints representing the user without ability to encrypt/decrypt secrets in **E2EE** mode.
|
|
||||||
- [Infisical Token](/documentation/platform/token): Provides short-lived, scoped CRUD access to the secrets of a specific project and environment.
|
- [Infisical Token](/documentation/platform/token): Provides short-lived, scoped CRUD access to the secrets of a specific project and environment.
|
||||||
|
- API Key: Provides full access to all endpoints representing the user without ability to encrypt/decrypt secrets for **E2EE** endpoints.
|
||||||
|
|
||||||
<AccordionGroup>
|
<Tabs>
|
||||||
<Accordion title="API Key">
|
<Tab title="Infisical Token">
|
||||||
|
The Infisical Token mode uses an Infisical Token to authenticate with the API.
|
||||||
|
|
||||||
|
To authenticate requests with Infisical using the Infisical Token, you must include your Infisical Token in the `Authorization` header of HTTP requests made to the platform with the value `Bearer <infisical_token>`.
|
||||||
|
|
||||||
|
You can obtain an Infisical Token in Project Settings > Service Tokens.
|
||||||
|
|
||||||
|

|
||||||
|
</Tab>
|
||||||
|
<Tab title="API Key">
|
||||||
The API key mode uses an API key to authenticate with the API.
|
The API key mode uses an API key to authenticate with the API.
|
||||||
|
|
||||||
To authenticate requests with Infisical using the API Key, you must include an API key in the `X-API-KEY` header of HTTP requests made to the platform.
|
To authenticate requests with Infisical using the API Key, you must include an API key in the `X-API-KEY` header of HTTP requests made to the platform.
|
||||||
@@ -20,15 +27,5 @@ You can obtain an API key in User Settings > API Keys
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||
</Accordion>
|
</Tab>
|
||||||
<Accordion title="Infisical Token">
|
</Tabs>
|
||||||
|
|
||||||
The Infisical Token mode uses an Infisical Token to authenticate with the API.
|
|
||||||
|
|
||||||
To authenticate requests with Infisical using the Infisical Token, you must include your Infisical Token in the `Authorization` header of HTTP requests made to the platform with the value `Bearer <infisical_token>`.
|
|
||||||
|
|
||||||
You can obtain an Infisical Token in Project Settings > Service Tokens.
|
|
||||||
|
|
||||||

|
|
||||||
</Accordion>
|
|
||||||
</AccordionGroup>
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ES Mode"
|
|
||||||
---
|
|
||||||
|
|
||||||
Encrypted Standard (ES) mode is the easiest way to use Infisical's API. With it, you can make HTTP calls to Infisical
|
|
||||||
to read/write secrets in plaintext.
|
|
||||||
|
|
||||||
Prerequisites:
|
|
||||||
|
|
||||||
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
|
|
||||||
- Create an [Infisical Token](/documentation/platform/token) for your project and environment with write access enabled.
|
|
||||||
- [Ensure that your project is blind-indexed](../blind-indices).
|
|
||||||
|
|
||||||
Below, we showcase how to execute common CRUD operations to manage secrets in **ES** mode:
|
|
||||||
|
|
||||||
<AccordionGroup>
|
|
||||||
<Accordion title="Retrieve secrets">
|
|
||||||
<Tabs>
|
|
||||||
<Tab title="cURL">
|
|
||||||
```bash
|
|
||||||
curl --location --request GET 'http://localhost:8080/api/v3/secrets/raw?environment=dev&workspaceId=xxx' \
|
|
||||||
--header 'Authorization: Bearer st.xxx'
|
|
||||||
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Create secret">
|
|
||||||
<Tabs>
|
|
||||||
<Tab title="cURL">
|
|
||||||
```bash
|
|
||||||
curl --location --request POST 'http://localhost:8080/api/v3/secrets/raw/SECRET_NAME' \
|
|
||||||
--header 'Authorization: Bearer st.xxx' \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
--data-raw '{
|
|
||||||
"workspaceId": "xxx",
|
|
||||||
"environment": "dev",
|
|
||||||
"type": "shared",
|
|
||||||
"secretValue": "SECRET_VALUE",
|
|
||||||
"secretPath": "/"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Retrieve secret">
|
|
||||||
<Tabs>
|
|
||||||
<Tab title="cURL">
|
|
||||||
```bash
|
|
||||||
curl --location --request GET 'http://localhost:8080/api/v3/secrets/raw/SECRET_NAME?workspaceId=xxx&environment=dev&secretPath=/' \
|
|
||||||
--header 'Authorization: Bearer st.xxx'
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Update secret">
|
|
||||||
<Tabs>
|
|
||||||
<Tab title="cURL">
|
|
||||||
```bash
|
|
||||||
curl --location --request PATCH 'http://localhost:8080/api/v3/secrets/raw/SECRET_NAME' \
|
|
||||||
--header 'Authorization: Bearer st.xxx' \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
--data-raw '{
|
|
||||||
"workspaceId": "xxx",
|
|
||||||
"environment": "dev",
|
|
||||||
"type": "shared",
|
|
||||||
"secretValue": "SECRET_VALUE",
|
|
||||||
"secretPath": "/"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Delete secret">
|
|
||||||
<Tabs>
|
|
||||||
<Tab title="cURL">
|
|
||||||
```bash
|
|
||||||
curl --location --request DELETE 'http://localhost:8080/api/v3/secrets/raw/SECRET_NAME' \
|
|
||||||
--header 'Authorization: Bearer st.xxx' \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
--data-raw '{
|
|
||||||
"workspaceId": "xxx",
|
|
||||||
"environment": "dev",
|
|
||||||
"type": "shared",
|
|
||||||
"secretValue": "SECRET_VALUE",
|
|
||||||
"secretPath": "/"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
</Accordion>
|
|
||||||
</AccordionGroup>
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Preface"
|
|
||||||
---
|
|
||||||
|
|
||||||
Each project in Infisical can be used either in **End-to-End Encrypted (E2EE)** mode or **Encrypted Standard (ES)** mode which dictates how it can be interacted with via the Infisical API.
|
|
||||||
|
|
||||||
<CardGroup cols={2}>
|
|
||||||
<Card
|
|
||||||
title="Encrypted Standard (ES)"
|
|
||||||
href="/api-reference/overview/encryption-modes/es-mode"
|
|
||||||
icon="shield-halved"
|
|
||||||
color="#3c8639"
|
|
||||||
>
|
|
||||||
Secret operations without client-side encryption/decryption
|
|
||||||
</Card>
|
|
||||||
<Card href="/api-reference/overview/encryption-modes/e2ee-mode" title="End-to-End Encrypted (E2EE)" icon="shield" color="#3775a9">
|
|
||||||
Secret operations with client-side encryption/decryption
|
|
||||||
</Card>
|
|
||||||
</CardGroup>
|
|
||||||
|
|
||||||
By default, all projects are initialized in **E2EE** mode which means the server is not able to decrypt any values because all secret encryption/decryption operations occur on the client-side. However, this has limitations around functionality and ease-of-use:
|
|
||||||
|
|
||||||
- You cannot make HTTP calls to Infisical to read/write secrets in plaintext.
|
|
||||||
- You cannot leverage non-E2EE features like native integrations and in-platform automations like dynamic secrets and secret rotation.
|
|
||||||
|
|
||||||
For this reason, Infisical also provides the **ES** mode of operation to unlock the above limitations by enabling the server to decrypt your values. You can optionally switch a project to using **ES** mode
|
|
||||||
in your Project Settings.
|
|
||||||
|
|
||||||
<Note>
|
|
||||||
Make no mistake, the limitations of **E2EE** mode do not prevent you from syncing secrets from Infisical to platforms like GitLab. They just imply
|
|
||||||
that you have to do things the "E2EE-way" such as by embedding the Infisical CLI into your GitLab CI/CD pipelines to fetch and decrypt
|
|
||||||
secrets on the client-side.
|
|
||||||
</Note>
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
<AccordionGroup>
|
|
||||||
<Accordion title="Is E2EE mode or ES mode right for me?">
|
|
||||||
We recommend starting with **E2EE** mode and switching to **ES** mode when:
|
|
||||||
|
|
||||||
- Your team needs more power out of non-E2EE features available in **ES** mode such as secret rotation, dynamic secrets, etc.
|
|
||||||
- Your team wants an easier way to read/write secrets with Infisical.
|
|
||||||
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="How can I switch from E2EE mode to ES mode?">
|
|
||||||
By default, all projects in Infisical are initialized to **E2EE** mode and can be switched to **ES** mode in the Project Settings by disabling end-to-end encryption.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Is ES mode secure if it's not E2EE?">
|
|
||||||
**ES** mode is secure and in fact what most vendors in the secret management industry are doing at the moment. In this mode, secrets are encrypted at rest by
|
|
||||||
a series of keys, secured ultimately by a top-level `ROOT_ENCRYPTION_KEY` located on the server.
|
|
||||||
|
|
||||||
If you're concerned about Infisical Cloud's ability to read your secrets if using **ES** mode in Infisical Cloud, then you may wish to
|
|
||||||
use Infisical Cloud in **E2EE** mode or self-host Infisical on your own infrastructure and then use **ES** mode; this of course which means setting up firewalls and securing the instance yourself.
|
|
||||||
|
|
||||||
As an organization, we prohibit reading any customer secrets without explicit permission; access to the `ROOT_ENCRYPTION_KEY` is restricted to one individual in the organization.
|
|
||||||
</Accordion>
|
|
||||||
</AccordionGroup>
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Create secret"
|
|
||||||
description: "How to add 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](/documentation/platform/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).
|
|
||||||
|
|
||||||
## Flow
|
|
||||||
|
|
||||||
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.
|
|
||||||
3. Encrypt your secret with the project key
|
|
||||||
4. [Send (encrypted) secret to Infisical](/api-reference/endpoints/secrets/create)
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
<Tabs>
|
|
||||||
<Tab title="Javascript">
|
|
||||||
```js
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const axios = require('axios');
|
|
||||||
const nacl = require('tweetnacl');
|
|
||||||
|
|
||||||
const BASE_URL = 'https://app.infisical.com';
|
|
||||||
const ALGORITHM = 'aes-256-gcm';
|
|
||||||
const BLOCK_SIZE_BYTES = 16;
|
|
||||||
|
|
||||||
const encrypt = ({ text, secret }) => {
|
|
||||||
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
|
|
||||||
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
|
|
||||||
|
|
||||||
let ciphertext = cipher.update(text, 'utf8', 'base64');
|
|
||||||
ciphertext += cipher.final('base64');
|
|
||||||
return {
|
|
||||||
ciphertext,
|
|
||||||
iv: iv.toString('base64'),
|
|
||||||
tag: cipher.getAuthTag().toString('base64')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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 createSecrets = async () => {
|
|
||||||
const serviceToken = '';
|
|
||||||
const serviceTokenSecret = serviceToken.substring(serviceToken.lastIndexOf('.') + 1);
|
|
||||||
|
|
||||||
const secretType = 'shared'; // 'shared' or 'personal'
|
|
||||||
const secretKey = 'some_key';
|
|
||||||
const secretValue = 'some_value';
|
|
||||||
const secretComment = 'some_comment';
|
|
||||||
|
|
||||||
// 1. Get your Infisical Token data
|
|
||||||
const { data: serviceTokenData } = await axios.get(
|
|
||||||
`${BASE_URL}/api/v2/service-token`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${serviceToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2. 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
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. Encrypt your secret with the project key
|
|
||||||
const {
|
|
||||||
ciphertext: secretKeyCiphertext,
|
|
||||||
iv: secretKeyIV,
|
|
||||||
tag: secretKeyTag
|
|
||||||
} = encrypt({
|
|
||||||
text: secretKey,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
ciphertext: secretValueCiphertext,
|
|
||||||
iv: secretValueIV,
|
|
||||||
tag: secretValueTag
|
|
||||||
} = encrypt({
|
|
||||||
text: secretValue,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
ciphertext: secretCommentCiphertext,
|
|
||||||
iv: secretCommentIV,
|
|
||||||
tag: secretCommentTag
|
|
||||||
} = encrypt({
|
|
||||||
text: secretComment,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. Send (encrypted) secret to Infisical
|
|
||||||
await axios.post(
|
|
||||||
`${BASE_URL}/api/v3/secrets/${secretKey}`,
|
|
||||||
{
|
|
||||||
workspaceId: serviceTokenData.workspace,
|
|
||||||
environment: serviceTokenData.environment,
|
|
||||||
type: secretType,
|
|
||||||
secretKeyCiphertext,
|
|
||||||
secretKeyIV,
|
|
||||||
secretKeyTag,
|
|
||||||
secretValueCiphertext,
|
|
||||||
secretValueIV,
|
|
||||||
secretValueTag,
|
|
||||||
secretCommentCiphertext,
|
|
||||||
secretCommentIV,
|
|
||||||
secretCommentTag
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${serviceToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
createSecrets();
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
|
|
||||||
<Tab title="Python">
|
|
||||||
```Python
|
|
||||||
import base64
|
|
||||||
import requests
|
|
||||||
from Cryptodome.Cipher import AES
|
|
||||||
from Cryptodome.Random import get_random_bytes
|
|
||||||
|
|
||||||
|
|
||||||
BASE_URL = "https://app.infisical.com"
|
|
||||||
BLOCK_SIZE_BYTES = 16
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(text, secret):
|
|
||||||
iv = get_random_bytes(BLOCK_SIZE_BYTES)
|
|
||||||
secret = bytes(secret, "utf-8")
|
|
||||||
cipher = AES.new(secret, AES.MODE_GCM, iv)
|
|
||||||
ciphertext, tag = cipher.encrypt_and_digest(text.encode("utf-8"))
|
|
||||||
return {
|
|
||||||
"ciphertext": base64.standard_b64encode(ciphertext).decode("utf-8"),
|
|
||||||
"tag": base64.standard_b64encode(tag).decode("utf-8"),
|
|
||||||
"iv": base64.standard_b64encode(iv).decode("utf-8"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 create_secrets():
|
|
||||||
service_token = "your_service_token"
|
|
||||||
service_token_secret = service_token[service_token.rindex(".") + 1 :]
|
|
||||||
|
|
||||||
secret_type = "shared" # "shared or "personal"
|
|
||||||
secret_key = "some_key"
|
|
||||||
secret_value = "some_value"
|
|
||||||
secret_comment = "some_comment"
|
|
||||||
|
|
||||||
# 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. 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,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 3. Encrypt your secret with the project key
|
|
||||||
encrypted_key_data = encrypt(text=secret_key, secret=project_key)
|
|
||||||
encrypted_value_data = encrypt(text=secret_value, secret=project_key)
|
|
||||||
encrypted_comment_data = encrypt(text=secret_comment, secret=project_key)
|
|
||||||
|
|
||||||
# 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,
|
|
||||||
"secretKeyCiphertext": encrypted_key_data["ciphertext"],
|
|
||||||
"secretKeyIV": encrypted_key_data["iv"],
|
|
||||||
"secretKeyTag": encrypted_key_data["tag"],
|
|
||||||
"secretValueCiphertext": encrypted_value_data["ciphertext"],
|
|
||||||
"secretValueIV": encrypted_value_data["iv"],
|
|
||||||
"secretValueTag": encrypted_value_data["tag"],
|
|
||||||
"secretCommentCiphertext": encrypted_comment_data["ciphertext"],
|
|
||||||
"secretCommentIV": encrypted_comment_data["iv"],
|
|
||||||
"secretCommentTag": encrypted_comment_data["tag"]
|
|
||||||
},
|
|
||||||
headers={"Authorization": f"Bearer {service_token}"},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
create_secrets()
|
|
||||||
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
---
|
|
||||||
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](/documentation/platform/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>
|
|
||||||
|
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
---
|
||||||
|
title: "E2EE Disabled"
|
||||||
|
---
|
||||||
|
|
||||||
|
Using Infisical's API to read/write secrets with E2EE disabled allows you to create, update, and retrieve secrets
|
||||||
|
in plaintext. Effectively, this means each such secret operation only requires 1 HTTP call.
|
||||||
|
|
||||||
|
<AccordionGroup>
|
||||||
|
<Accordion title="Retrieve secrets">
|
||||||
|
Retrieve all secrets for an Infisical project and environment.
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="cURL">
|
||||||
|
```bash
|
||||||
|
curl --location --request GET 'https://app.infisical.com/api/v3/secrets/raw?environment=environment&workspaceId=workspaceId' \
|
||||||
|
--header 'Authorization: Bearer serviceToken'
|
||||||
|
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
<ParamField query="workspaceId" type="string" required>
|
||||||
|
The ID of the workspace
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="environment" type="string" required>
|
||||||
|
The environment slug
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="secretPath" type="string" default="/" optional>
|
||||||
|
Path to secrets in workspace
|
||||||
|
</ParamField>
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Create secret">
|
||||||
|
Create a secret in Infisical.
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="cURL">
|
||||||
|
```bash
|
||||||
|
curl --location --request POST 'https://app.infisical.com/api/v3/secrets/raw/secretName' \
|
||||||
|
--header 'Authorization: Bearer serviceToken' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"workspaceId": "workspaceId",
|
||||||
|
"environment": "environment",
|
||||||
|
"type": "shared",
|
||||||
|
"secretValue": "secretValue",
|
||||||
|
"secretPath": "/"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
<ParamField path="secretName" type="string" required>
|
||||||
|
Name of secret to create
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="workspaceId" type="string" required>
|
||||||
|
The ID of the workspace
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="environment" type="string" required>
|
||||||
|
The environment slug
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="secretValue" type="string" required>
|
||||||
|
Value of secret
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="secretComment" type="string" optional>
|
||||||
|
Comment of secret
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="secretPath" type="string" default="/" optional>
|
||||||
|
Path to secret in workspace
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="type" type="string" optional default="shared">
|
||||||
|
The type of the secret. Valid options are “shared” or “personal”
|
||||||
|
</ParamField>
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Retrieve secret">
|
||||||
|
Retrieve a secret from Infisical.
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="cURL">
|
||||||
|
```bash
|
||||||
|
curl --location --request GET 'https://app.infisical.com/api/v3/secrets/raw/secretName?workspaceId=workspaceId&environment=environment' \
|
||||||
|
--header 'Authorization: Bearer serviceToken'
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
<ParamField path="secretName" type="string" required>
|
||||||
|
Name of secret to retrieve
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="workspaceId" type="string" required>
|
||||||
|
The ID of the workspace
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="environment" type="string" required>
|
||||||
|
The environment slug
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="secretPath" type="string" default="/" optional>
|
||||||
|
Path to secrets in workspace
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="type" type="string" optional default="personal">
|
||||||
|
The type of the secret. Valid options are “shared” or “personal”
|
||||||
|
</ParamField>
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Update secret">
|
||||||
|
Update an existing secret in Infisical.
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="cURL">
|
||||||
|
```bash
|
||||||
|
curl --location --request PATCH 'https://app.infisical.com/api/v3/secrets/raw/secretName' \
|
||||||
|
--header 'Authorization: Bearer serviceToken' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"workspaceId": "workspaceId",
|
||||||
|
"environment": "environment",
|
||||||
|
"type": "shared",
|
||||||
|
"secretValue": "secretValue",
|
||||||
|
"secretPath": "/"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
<ParamField path="secretName" type="string" required>
|
||||||
|
Name of secret to update
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="workspaceId" type="string" required>
|
||||||
|
The ID of the workspace
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="environment" type="string" required>
|
||||||
|
The environment slug
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="secretValue" type="string" required>
|
||||||
|
Value of secret
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="secretPath" type="string" default="/" optional>
|
||||||
|
Path to secret in workspace.
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="type" type="string" optional default="shared">
|
||||||
|
The type of the secret. Valid options are “shared” or “personal”
|
||||||
|
</ParamField>
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Delete secret">
|
||||||
|
Delete a secret in Infisical.
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="cURL">
|
||||||
|
```bash
|
||||||
|
curl --location --request DELETE 'https://app.infisical.com/api/v3/secrets/raw/secretName' \
|
||||||
|
--header 'Authorization: Bearer serviceToken' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"workspaceId": "workspaceId",
|
||||||
|
"environment": "environment",
|
||||||
|
"type": "shared",
|
||||||
|
"secretPath": "/"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
<ParamField path="secretName" type="string" required>
|
||||||
|
Name of secret to update
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="workspaceId" type="string" required>
|
||||||
|
The ID of the workspace
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="environment" type="string" required>
|
||||||
|
The environment slug
|
||||||
|
</ParamField>
|
||||||
|
<ParamField body="secretPath" type="string" default="/" optional>
|
||||||
|
Path to secret in workspace.
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="type" type="string" optional default="personal">
|
||||||
|
The type of the secret. Valid options are “shared” or “personal”
|
||||||
|
</ParamField>
|
||||||
|
</Accordion>
|
||||||
|
</AccordionGroup>
|
||||||
+9
-12
@@ -1,23 +1,16 @@
|
|||||||
---
|
---
|
||||||
title: "E2EE Mode"
|
title: "E2EE Enabled"
|
||||||
---
|
---
|
||||||
|
|
||||||
End-to-End Encrypted (E2EE) mode is the default way to use Infisical's API. With it, you must perform client-side encryption/decryption
|
Using Infisical's API to read/write secrets with E2EE enabled allows you to create, update, and retrieve secrets
|
||||||
when reading/writing secrets via HTTP call to Infisical.
|
but requires you to perform client-side encryption/decryption operations. For this reason, we recommend using one of the available
|
||||||
|
SDKs instead.
|
||||||
Prerequisites:
|
|
||||||
|
|
||||||
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
|
|
||||||
- Create an [Infisical Token](/documentation/platform/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).
|
|
||||||
|
|
||||||
Below, we showcase how to execute common CRUD operations to manage secrets in **E2EE** mode:
|
|
||||||
|
|
||||||
<AccordionGroup>
|
<AccordionGroup>
|
||||||
<Accordion title="Retrieve secrets">
|
<Accordion title="Retrieve secrets">
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="Javascript">
|
<Tab title="Javascript">
|
||||||
|
Retrieve all secrets for an Infisical project and environment.
|
||||||
```js
|
```js
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
@@ -194,6 +187,7 @@ get_secrets()
|
|||||||
<Accordion title="Create secret">
|
<Accordion title="Create secret">
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="Javascript">
|
<Tab title="Javascript">
|
||||||
|
Create a secret in Infisical.
|
||||||
```js
|
```js
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
@@ -408,6 +402,7 @@ create_secrets()
|
|||||||
<Accordion title="Retrieve secret">
|
<Accordion title="Retrieve secret">
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="Javascript">
|
<Tab title="Javascript">
|
||||||
|
Retrieve a secret from Infisical.
|
||||||
```js
|
```js
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
@@ -569,6 +564,7 @@ get_secret()
|
|||||||
<Accordion title="Update secret">
|
<Accordion title="Update secret">
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="Javascript">
|
<Tab title="Javascript">
|
||||||
|
Update an existing secret in Infisical.
|
||||||
```js
|
```js
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
@@ -779,6 +775,7 @@ update_secret()
|
|||||||
<Accordion title="Delete secret">
|
<Accordion title="Delete secret">
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="Javascript">
|
<Tab title="Javascript">
|
||||||
|
Delete a secret in Infisical.
|
||||||
```js
|
```js
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const BASE_URL = 'https://app.infisical.com';
|
const BASE_URL = 'https://app.infisical.com';
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
title: "Note on E2EE"
|
||||||
|
---
|
||||||
|
|
||||||
|
Each project in Infisical can have **End-to-End Encryption (E2EE)** enabled or disabled.
|
||||||
|
|
||||||
|
By default, all projects have **E2EE** enabled which means the server is not able to decrypt any values because all secret encryption/decryption operations occur on the client-side; this can be (optionally) disabled. However, this has limitations around functionality and ease-of-use:
|
||||||
|
|
||||||
|
- You cannot make HTTP calls to Infisical to read/write secrets in plaintext.
|
||||||
|
- You cannot leverage non-E2EE features like native integrations and in-platform automations like dynamic secrets and secret rotation.
|
||||||
|
|
||||||
|
<CardGroup cols={2}>
|
||||||
|
<Card
|
||||||
|
title="E2EE Disabled"
|
||||||
|
href="/api-reference/overview/examples/e2ee-disabled"
|
||||||
|
icon="shield-halved"
|
||||||
|
color="#3c8639"
|
||||||
|
>
|
||||||
|
Example read/write secrets without client-side encryption/decryption
|
||||||
|
</Card>
|
||||||
|
<Card
|
||||||
|
href="/api-reference/overview/examples/e2ee-enabled"
|
||||||
|
title="E2EE Enabled"
|
||||||
|
icon="shield"
|
||||||
|
color="#3775a9"
|
||||||
|
>
|
||||||
|
Example read/write secrets with client-side encryption/decryption
|
||||||
|
</Card>
|
||||||
|
</CardGroup>
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
<AccordionGroup>
|
||||||
|
<Accordion title="Should I have E2EE enabled or disabled?">
|
||||||
|
We recommend starting with having **E2EE** enabled and disabling it if:
|
||||||
|
|
||||||
|
- You're self-hosting Infisical, so having your instance of Infisical be able to read your secrets isn't an issue.
|
||||||
|
- You want an easier way to read/write secrets with Infisical.
|
||||||
|
- You need more power out of non-E2EE features such as secret rotation, dynamic secrets, etc.
|
||||||
|
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="How can I enable/disable E2EE?">
|
||||||
|
You can enable/disable E2EE for your project in Infisical in the Project Settings.
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Is disabling E2EE secure?">
|
||||||
|
It is secure and in fact how most vendors in our industry are able to offer features like secret rotation. In this mode, secrets are encrypted at rest by
|
||||||
|
a series of keys, secured ultimately by a top-level `ROOT_ENCRYPTION_KEY` located on the server.
|
||||||
|
|
||||||
|
If you're concerned about Infisical Cloud's ability to read your secrets, then you may wish to
|
||||||
|
use it with **E2EE** enabled or self-host Infisical on your own infrastructure and disable E2EE there.
|
||||||
|
|
||||||
|
As an organization, we do not read any customer secrets without explicit permission; access to the `ROOT_ENCRYPTION_KEY` is restricted to one individual in the organization.
|
||||||
|
</Accordion>
|
||||||
|
</AccordionGroup>
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
---
|
|
||||||
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](/documentation/platform/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,195 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Retrieve secrets"
|
|
||||||
description: "How to get all secrets 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](/documentation/platform/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 secrets for your project and environment](/api-reference/endpoints/secrets/read).
|
|
||||||
3. Decrypt the (encrypted) project key with the key from your Infisical Token.
|
|
||||||
4. Decrypt the (encrypted) secrets
|
|
||||||
|
|
||||||
## 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 getSecrets = async () => {
|
|
||||||
const serviceToken = 'your_service_token';
|
|
||||||
const serviceTokenSecret = serviceToken.substring(serviceToken.lastIndexOf('.') + 1);
|
|
||||||
|
|
||||||
// 1. Get your Infisical Token data
|
|
||||||
const { data: serviceTokenData } = await axios.get(
|
|
||||||
`${BASE_URL}/api/v2/service-token`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${serviceToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2. Get secrets for your project and environment
|
|
||||||
const { data } = await axios.get(
|
|
||||||
`${BASE_URL}/api/v3/secrets?${new URLSearchParams({
|
|
||||||
environment: serviceTokenData.environment,
|
|
||||||
workspaceId: serviceTokenData.workspace
|
|
||||||
})}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${serviceToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const encryptedSecrets = data.secrets;
|
|
||||||
|
|
||||||
// 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) secrets
|
|
||||||
const secrets = encryptedSecrets.map((secret) => {
|
|
||||||
const secretKey = decrypt({
|
|
||||||
ciphertext: secret.secretKeyCiphertext,
|
|
||||||
iv: secret.secretKeyIV,
|
|
||||||
tag: secret.secretKeyTag,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
const secretValue = decrypt({
|
|
||||||
ciphertext: secret.secretValueCiphertext,
|
|
||||||
iv: secret.secretValueIV,
|
|
||||||
tag: secret.secretValueTag,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
return ({
|
|
||||||
secretKey,
|
|
||||||
secretValue
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('secrets: ', secrets);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSecrets();
|
|
||||||
|
|
||||||
```
|
|
||||||
</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_secrets():
|
|
||||||
service_token = "your_service_token"
|
|
||||||
service_token_secret = service_token[service_token.rindex(".") + 1 :]
|
|
||||||
|
|
||||||
# 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 secrets for your project and environment
|
|
||||||
data = requests.get(
|
|
||||||
f"{BASE_URL}/api/v3/secrets",
|
|
||||||
params={
|
|
||||||
"environment": service_token_data["environment"],
|
|
||||||
"workspaceId": service_token_data["workspace"],
|
|
||||||
},
|
|
||||||
headers={"Authorization": f"Bearer {service_token}"},
|
|
||||||
).json()
|
|
||||||
|
|
||||||
encrypted_secrets = data["secrets"]
|
|
||||||
|
|
||||||
# 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) secrets
|
|
||||||
secrets = []
|
|
||||||
for secret in encrypted_secrets:
|
|
||||||
secret_key = decrypt(
|
|
||||||
ciphertext=secret["secretKeyCiphertext"],
|
|
||||||
iv=secret["secretKeyIV"],
|
|
||||||
tag=secret["secretKeyTag"],
|
|
||||||
secret=project_key,
|
|
||||||
)
|
|
||||||
|
|
||||||
secret_value = decrypt(
|
|
||||||
ciphertext=secret["secretValueCiphertext"],
|
|
||||||
iv=secret["secretValueIV"],
|
|
||||||
tag=secret["secretValueTag"],
|
|
||||||
secret=project_key,
|
|
||||||
)
|
|
||||||
|
|
||||||
secrets.append(
|
|
||||||
{
|
|
||||||
"secret_key": secret_key,
|
|
||||||
"secret_value": secret_value,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
print("secrets:", secrets)
|
|
||||||
|
|
||||||
|
|
||||||
get_secrets()
|
|
||||||
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Update secret"
|
|
||||||
description: "How to update 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](/documentation/platform/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).
|
|
||||||
|
|
||||||
## Flow
|
|
||||||
|
|
||||||
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.
|
|
||||||
3. Encrypt your updated secret with the project key
|
|
||||||
4. [Send (encrypted) updated secret to Infical](/api-reference/endpoints/secrets/update)
|
|
||||||
|
|
||||||
## 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 BLOCK_SIZE_BYTES = 16;
|
|
||||||
|
|
||||||
const encrypt = ({ text, secret }) => {
|
|
||||||
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
|
|
||||||
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
|
|
||||||
|
|
||||||
let ciphertext = cipher.update(text, 'utf8', 'base64');
|
|
||||||
ciphertext += cipher.final('base64');
|
|
||||||
return {
|
|
||||||
ciphertext,
|
|
||||||
iv: iv.toString('base64'),
|
|
||||||
tag: cipher.getAuthTag().toString('base64')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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 updateSecrets = async () => {
|
|
||||||
const serviceToken = 'your_service_token';
|
|
||||||
const serviceTokenSecret = serviceToken.substring(serviceToken.lastIndexOf('.') + 1);
|
|
||||||
|
|
||||||
const secretType = 'shared' // 'shared' or 'personal'
|
|
||||||
const secretKey = 'some_key';
|
|
||||||
const secretValue = 'updated_value';
|
|
||||||
const secretComment = 'updated_comment';
|
|
||||||
|
|
||||||
// 1. Get your Infisical Token data
|
|
||||||
const { data: serviceTokenData } = await axios.get(
|
|
||||||
`${BASE_URL}/api/v2/service-token`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${serviceToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2. 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
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. Encrypt your updated secret with the project key
|
|
||||||
const {
|
|
||||||
ciphertext: secretKeyCiphertext,
|
|
||||||
iv: secretKeyIV,
|
|
||||||
tag: secretKeyTag
|
|
||||||
} = encrypt({
|
|
||||||
text: secretKey,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
ciphertext: secretValueCiphertext,
|
|
||||||
iv: secretValueIV,
|
|
||||||
tag: secretValueTag
|
|
||||||
} = encrypt({
|
|
||||||
text: secretValue,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
ciphertext: secretCommentCiphertext,
|
|
||||||
iv: secretCommentIV,
|
|
||||||
tag: secretCommentTag
|
|
||||||
} = encrypt({
|
|
||||||
text: secretComment,
|
|
||||||
secret: projectKey
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. Send (encrypted) updated secret to Infisical
|
|
||||||
await axios.patch(
|
|
||||||
`${BASE_URL}/api/v3/secrets/${secretKey}`,
|
|
||||||
{
|
|
||||||
workspaceId: serviceTokenData.workspace,
|
|
||||||
environment: serviceTokenData.environment,
|
|
||||||
type: secretType,
|
|
||||||
secretValueCiphertext,
|
|
||||||
secretValueIV,
|
|
||||||
secretValueTag,
|
|
||||||
secretCommentCiphertext,
|
|
||||||
secretCommentIV,
|
|
||||||
secretCommentTag
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${serviceToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSecrets();
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
|
|
||||||
<Tab title="Python">
|
|
||||||
```Python
|
|
||||||
import base64
|
|
||||||
import requests
|
|
||||||
from Cryptodome.Cipher import AES
|
|
||||||
from Cryptodome.Random import get_random_bytes
|
|
||||||
|
|
||||||
|
|
||||||
BASE_URL = "https://app.infisical.com"
|
|
||||||
BLOCK_SIZE_BYTES = 16
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(text, secret):
|
|
||||||
iv = get_random_bytes(BLOCK_SIZE_BYTES)
|
|
||||||
secret = bytes(secret, "utf-8")
|
|
||||||
cipher = AES.new(secret, AES.MODE_GCM, iv)
|
|
||||||
ciphertext, tag = cipher.encrypt_and_digest(text.encode("utf-8"))
|
|
||||||
return {
|
|
||||||
"ciphertext": base64.standard_b64encode(ciphertext).decode("utf-8"),
|
|
||||||
"tag": base64.standard_b64encode(tag).decode("utf-8"),
|
|
||||||
"iv": base64.standard_b64encode(iv).decode("utf-8"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 update_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"
|
|
||||||
secret_value = "updated_value"
|
|
||||||
secret_comment = "updated_comment"
|
|
||||||
|
|
||||||
# 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. 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,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 3. Encrypt your updated secret with the project key
|
|
||||||
encrypted_key_data = encrypt(text=secret_key, secret=project_key)
|
|
||||||
encrypted_value_data = encrypt(text=secret_value, secret=project_key)
|
|
||||||
encrypted_comment_data = encrypt(text=secret_comment, secret=project_key)
|
|
||||||
|
|
||||||
# 4. Send (encrypted) updated secret to Infisical
|
|
||||||
requests.patch(
|
|
||||||
f"{BASE_URL}/api/v3/secrets/{secret_key}",
|
|
||||||
json={
|
|
||||||
"workspaceId": service_token_data["workspace"],
|
|
||||||
"environment": service_token_data["environment"],
|
|
||||||
"type": secret_type,
|
|
||||||
"secretKeyCiphertext": encrypted_key_data["ciphertext"],
|
|
||||||
"secretKeyIV": encrypted_key_data["iv"],
|
|
||||||
"secretKeyTag": encrypted_key_data["tag"],
|
|
||||||
"secretValueCiphertext": encrypted_value_data["ciphertext"],
|
|
||||||
"secretValueIV": encrypted_value_data["iv"],
|
|
||||||
"secretValueTag": encrypted_value_data["tag"],
|
|
||||||
"secretCommentCiphertext": encrypted_comment_data["ciphertext"],
|
|
||||||
"secretCommentIV": encrypted_comment_data["iv"],
|
|
||||||
"secretCommentTag": encrypted_comment_data["tag"]
|
|
||||||
},
|
|
||||||
headers={"Authorization": f"Bearer {service_token}"},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
update_secret()
|
|
||||||
|
|
||||||
```
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
+3
-3
@@ -250,9 +250,9 @@
|
|||||||
{
|
{
|
||||||
"group": "Examples",
|
"group": "Examples",
|
||||||
"pages": [
|
"pages": [
|
||||||
"api-reference/overview/encryption-modes/overview",
|
"api-reference/overview/examples/note",
|
||||||
"api-reference/overview/encryption-modes/es-mode",
|
"api-reference/overview/examples/e2ee-disabled",
|
||||||
"api-reference/overview/encryption-modes/e2ee-mode"
|
"api-reference/overview/examples/e2ee-enabled"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"api-reference/overview/blind-indices"
|
"api-reference/overview/blind-indices"
|
||||||
|
|||||||
Reference in New Issue
Block a user