- [Сравнение с альтернативами](#сравнение-с-альтернативами)
- [Работа с Git](#работа-с-git)
- [Индикатор статуса KMS](#индикатор-статуса-kms)
- [Известные ограничения](#известные-ограничения)
- [Development](#development)
- [Лицензия](LICENSE)
## Зачем
Если вы храните Obsidian-хранилище в S3, Git или любом другом удалённом хранилище — содержимое заметок доступно любому, кто получит доступ к storage. Этот плагин реализует модель **Zero Trust Storage**: на диске и в remote всегда лежит только шифротекст. Расшифровка происходит локально, в памяти, только при наличии доступа к Cloud KMS.
## Ключевые принципы
- **Envelope Encryption** — каждый блок/файл шифруется уникальным DEK (AES-256-GCM), а сам DEK оборачивается CMK в облачном KMS
- **Identity-based Auth** — никаких паролей; используются системные credentials (AWS SSO, IAM Role, `~/.aws/credentials`)
- **Local-First Crypto** — симметричное шифрование выполняется локально через WebCrypto API; в KMS уходит только DEK для wrap/unwrap
- **Zero Cleartext on Disk** — расшифрованный контент существует только в оперативной памяти процесса Obsidian
- **Transparent** — шифрование/расшифровка происходит автоматически при чтении/записи файлов (monkey-patch vault adapter)
- **Nested Content** — маркеры `%%secret-start%%` / `%%secret-end%%` не конфликтуют с code fences, позволяя вкладывать ```mermaid, ```js и любой другой markdown
## Как работает
### Markdown-файлы (секретные блоки)
Плагин перехватывает чтение и запись файлов на уровне Obsidian vault adapter:
- **При записи на диск**: все блоки между `%%secret-start%%` и `%%secret-end%%` автоматически шифруются → на диске хранятся как `ocke-v1` блок
- **При чтении с диска**: все `ocke-v1` блоки автоматически расшифровываются → в редакторе показываются между `%%secret-start%%` / `%%secret-end%%`
### Бинарные файлы (PDF, изображения, аудио)
- Команда **"Encrypt current file"** шифрует файл на месте (имя не меняется)
- При открытии — файл расшифровывается в памяти (Blob URL), Obsidian показывает его как обычно
-На диске всегда зашифрованные байты в формате OCKE
-В file explorer зашифрованные файлы отмечены 🔒
## Команды
| Команда | Описание |
|---------|----------|
| **Wrap selection in secret block** | Оборачивает выделенный текст в `%%secret-start%%` / `%%secret-end%%` |
| **Encrypt current file with AWS KMS** | Шифрует бинарный файл (PDF, PNG, MP3) на месте |
| **Decrypt current file with AWS KMS (permanent)** | Расшифровывает бинарный файл навсегда (записывает plaintext на диск) |
## Использование
### Шифрование текста в заметках
1. Выделите текст в заметке
2.`Ctrl+P` → **"Wrap selection in secret block"**
3. Текст оборачивается в `%%secret-start%%` / `%%secret-end%%` маркеры
4. При сохранении — автоматически шифруется на диске
### Ручное создание секретного блока
Просто оберните текст в маркеры:
```markdown
# Моя заметка
Это публичный текст.
%%secret-start%%
Это секретный контент — будет зашифрован при сохранении.
Пароли, токены, приватные заметки — всё что угодно.
%%secret-end%%
А это снова публичный текст.
```
### Вложенные code fences (mermaid, code и т.д.)
Маркеры `%%` — это Obsidian-комментарии, невидимые в Reading view. Содержимое между ними — обычный markdown, который рендерится нормально:
````markdown
%%secret-start%%
# Секретная архитектура
```mermaid
graph TD
A[Client] --> B[API Gateway]
B --> C[Lambda]
C --> D[DynamoDB]
```
```bash
export SECRET_KEY="my-super-secret-key"
aws s3 cp secret.tar.gz s3://my-bucket/
```
Пароль от продакшена: `P@ssw0rd123!`
%%secret-end%%
````
После сохранения весь блок (включая mermaid-диаграмму и код) будет зашифрован на диске. При открытии — расшифрован, и mermaid отрендерится как диаграмма в Reading view.
### Шифрование бинарных файлов
1. Откройте PDF, изображение или другой бинарный файл
2.`Ctrl+P` → **"Encrypt current file with AWS KMS"**
3. Файл зашифрован на месте (имя не меняется, в file explorer появляется 🔒)
4. При следующем открытии — расшифровывается в памяти, отображается как обычно
Для **постоянной** расшифровки (записать plaintext обратно на диск):
-`Ctrl+P` → **"Decrypt current file with AWS KMS (permanent)"**
### Удаление шифрования текста
1. Выделите весь блок (от `%%secret-start%%` до `%%secret-end%%`)
2.`Ctrl+P` → **"Unwrap secret block"**
3. Маркеры убираются, текст остаётся как обычный markdown (больше не шифруется)
## Поведение
| Ситуация | Результат |
|----------|-----------|
| Сохранение .md с`%%secret-start%%` блоками | Блоки шифруются → на диске `ocke-v1` блок |
| Открытие .md с`ocke-v1` блоками (ключ доступен) | Расшифровываются → в редакторе `%%secret-start%%...%%secret-end%%` |
| Открытие .md с`ocke-v1` блоками (ключ НЕ доступен) | Остаются как `ocke-v1` (зашифрованный base64) |
| Открытие зашифрованного PDF/PNG (ключ доступен) | Расшифровывается в памяти → отображается нормально |
| Открытие зашифрованного PDF/PNG (ключ НЕ доступен) | Obsidian не может отрендерить файл |
| KMS недоступен при сохранении | Файл сохраняется как есть, ошибка показывается |
| Каждый блок/файл | Шифруется независимо (свой DEK) |
| File explorer | Зашифрованные бинарные файлы отмечены 🔒 |
## Установка
### Требования
- Obsidian ≥ 1.4.0 (desktop)
- AWS credentials настроены (`~/.aws/credentials` или `aws sso login`)
### Из GitHub Releases
1. Перейдите в [Releases](https://github.com/ViktorUJ/obsidian-cloud-kms/releases)
# Никогда не игнорируйте эти файлы (это и есть зашифрованный vault):
# !*.md
# !attachments/
```
### Pre-commit hook: защита от утечки plaintext
Если плагин был выключен, credentials истекли, или файл редактировался вне Obsidian — маркеры `%%secret-start%%` могут оказаться на диске незашифрованными. Pre-commit hook предотвращает случайный коммит plaintext в Git:
```bash
# Установить hook
cp tools/pre-commit-hook.sh .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
```
Что делает:
- При каждом `git commit` проверяет все staged `.md` файлы
- Если в файле найден `%%secret-start%%` — **блокирует коммит**
- Показывает какой файл содержит незашифрованный контент и как исправить
Пример вывода при обнаружении plaintext:
```
ERROR: Plaintext secret block found in staged file: notes/budget.md
The file contains %%secret-start%% markers which means
the encryption plugin did not encrypt before save.
Fix: Open the file in Obsidian with the plugin enabled,
save it, then stage again.
Commit blocked: plaintext secrets detected.
```
> Это страховочная сетка — если всё работает правильно, `%%secret-start%%` никогда не должен появляться на диске (adapter patch шифрует его в `ocke-v1` блок перед записью). Hook ловит edge cases.
## CLI-расшифровка (без Obsidian)
Для disaster recovery, CI/CD пайплайнов или проверки бэкапов — можно расшифровать файлы без Obsidian через CLI.
> **Важно:** Encryption context (`vault-name` и `file-path`) должен совпадать с тем, что использовался при шифровании. Vault name — это имя папки вашего Obsidian vault. File path — путь относительно корня vault (например, `folder/note.md`).
### Вариант 1: Bash + AWS CLI + Python
Без Node.js. Требуется: `aws` CLI, `python3`, `pip install cryptography`.
| `-o <output>` | Записать результат в файл (по умолчанию: stdout) | Нет |
| `--vault-name` | Имя Obsidian vault (имя папки) | Да |
| `--file-path` | Путь файла относительно корня vault (как при шифровании) | Да |
Или через переменные окружения: `OCKE_VAULT_NAME`, `OCKE_FILE_PATH`.
> **Как узнать правильные значения:**
> - `vault-name` — имя папки vault (например, если vault в `/home/user/my-vault/`, имя — `my-vault`)
> - `file-path` — путь относительно корня vault (например, `notes/secret.md`, `attachments/report.pdf`)
### Когда использовать CLI
- **Disaster recovery** — Obsidian недоступен, нужен доступ к зашифрованным данным
- **CI/CD пайплайны** — расшифровка секретов при деплое без GUI
- **Проверка бэкапов** — убедиться что зашифрованные бэкапы валидны
- **Миграция** — массовая расшифровка при переходе с плагина
### Ротация ключей / Миграция (ocke-rekey)
Перешифровка всего vault новым KMS-ключом — для миграции на новый AWS-аккаунт, ротации ключей или смены региона. Перешифровывается только wrapped DEK (быстро), ciphertext не меняется.
- AWS credentials с`kms:Decrypt` на старом ключе И `kms:Encrypt` на новом
-Оба ключа должны быть доступны одновременно во время миграции
- После миграции обновите настройки плагина с новым ARN ключа
> **Примечание:** На Windows используйте Git Bash или WSL для корректной работы с Unicode-путями.
> Оба инструмента используют те же AWS credentials что и плагин (`~/.aws/credentials`).
> ARN ключа хранится внутри зашифрованных данных — конфигурация ключа не нужна.
## Индикатор статуса KMS
Плагин отображает индикатор состояния соединения в нижней панели Obsidian:
| Индикатор | Значение |
|-----------|----------|
| 🔓 KMS | Соединение OK — шифрование/расшифровка доступны |
| 🔒 KMS ⚠️ | KMS недоступен — секретные блоки НЕ будут зашифрованы при сохранении! |
| ⏳ KMS | Проверка соединения... |
**Поведение:**
- Проверяет доступность KMS при загрузке плагина
- Перепроверяет каждые 5 минут в фоне
- Клик по индикатору — ручная перепроверка
- При наведении — подробный tooltip
**Почему это важно:**
Если KMS недоступен (проблемы с сетью, истёкшие credentials, сбой AWS), плагин не может зашифровать `%%secret-start%%` блоки при сохранении. Файл будет сохранён с plaintext-маркерами. Индикатор статуса даёт мгновенную видимость этого риска — если видите 🔒 ⚠️, не сохраняйте файлы с секретными блоками до восстановления связи.
## Известные ограничения
### Monkey-patching Vault Adapter
Плагин перехватывает `vault.adapter.read()` и `vault.adapter.write()` для обеспечения прозрачного шифрования. Это тот же подход, что использует [gpgCrypt](https://github.com/tejado/obsidian-gpgCrypt) — единственный способ гарантировать zero-plaintext-on-disk без официального encryption API от Obsidian.
**Потенциальные конфликты с другими плагинами:**
- Если другой плагин тоже патчит `adapter.read()` или `adapter.write()`, два патча могут конфликтовать
- Плагин корректно вызывает оригинальный метод после обработки (chaining), но порядок инициализации имеет значение
- При проблемах попробуйте отключить другие плагины, модифицирующие файловый I/O
**Меры защиты:**
- Патч обрабатывает только `.md` файлы для текстового шифрования (бинарные проверяются по magic bytes)
- Файлы без маркеров `%%secret-start%%` или OCKE magic bytes проходят без изменений (нулевой overhead)
- При выгрузке плагина оригинальные методы adapter полностью восстанавливаются
- Патч прозрачен — другие плагины, работающие с незашифрованными файлами, не затрагиваются
**Если обновление Obsidian сломает плагин:**
- Ваши данные в безопасности — файлы остаются зашифрованными на диске в документированном формате OCKE
- Используйте [CLI-инструменты](#cli-расшифровка-без-obsidian) для расшифровки без Obsidian
- Плагин будет обновлён под новые internals Obsidian
## Development
```bash
npm test # Запуск тестов
npm run build # Production build
npm run dev # Dev build (watch)
make ci # Full CI pipeline
```
## Управление доступом к ключу
### Мульти-ключевая архитектура
В организациях разным командам нужен доступ к разным секретам. Плагин поддерживает несколько KMS-ключей, обеспечивая гранулярный контроль доступа:
**Кейс:** Общий vault компании, расшаренный между командами:
- **Финансовый отдел** — доступ к бюджетам, зарплатам, контрактам
- **R&D** — доступ к патентам, исследованиям, техническим секретам
- **CTO** — доступ ко всему (все ключи)
Каждый секретный блок шифруется конкретным ключом. IAM-политики на стороне AWS контролируют, кто может расшифровать что. Разработчик из R&D физически не может расшифровать финансовые данные — даже если у него есть доступ к файлам vault.