# 1Password
## Security
The data is encrypted with an **account password** and a **Secret Key**. We need **both** to decrypt our data.
- **Your 1Password account password protects your data on your devices.** Someone who has access to your devices or backups won’t be able to unlock 1Password without your account password, which only you know.
- **Your Secret Key protects your data off your devices.** Someone who attempts a brute-force attack on our servers won’t be able to decrypt your data without your Secret Key, which we never have.
![[Pasted image 20230812060241.png|Thanks to David Schuetz for reverse engeneering the cryptography workflow]]
> [!info] #todo/wiki 1Password added another mechanism how to access the vault – recovery keys [ref1](https://blog.1password.com/introducing-1password-recovery-codes/) and [ref2](https://www.reddit.com/r/1Password/s/7DGpbUoIZu).
Like your account password, your Secret Key is never sent to 1Password servers. But because you can’t memorize your Secret Key, 1Password stores copies of it for you, so you can:
- **Unlock 1Password without entering your Secret Key every time.** It’s stored in the 1Password apps and browsers you’ve used to sign in to your account on 1Password.com.
- **Have peace of mind if you lose a device.** Encrypted copies of your Secret Key are stored in your device backups and keychains to provide data loss protection. If you have iCloud Keychain turned on and lose your Mac, iPhone, or iPad, you can restore from a backup and unlock 1Password with just your account password. It’s the same for Android backups.
> [!info]
>
> When you use Touch ID or Apple Watch to unlock, 1Password stores an **encrypted secret** on disk. **This secret is used to decrypt your 1Password data when your fingerprint is recognized**, or you approve 1Password on Apple Watch. In 1Password 7 and later, the secret is encrypted using an encryption key stored in the Secure Enclave, which only 1Password can access.
>
> To decrypt the secret, 1Password proves its identity using code signatures, and then it moves the encrypted secret to the Secure Enclave. The secret is decrypted using the encryption key and returned to 1Password to decrypt your data.
> > The **encrypted secret** is **Master Unlock key** derived from **account password** and **Secret key**.
If we want to login on 1p website UI in anonymous mode, we need both **Secret Key** an **account password**:
![[Pasted image 20230812052424.png|1Password login screen|500]]
### Secret accounts
Secret accounts can be generated [here](https://my.1password.com/integrations/infrastructure-secrets/serviceaccount/) to allow us access vault content programmatically. It can be scoped to see 1 or more vaults (AFAIK there is no limit on amount of vaults) and whether it's read-only or read-write access.
Typically, authentication with 1Password requires your account password as well as your locally held Secret Key. **When you create a service account, the account password and Secret Key for the service account are randomly generated and the account password is discarded after deriving the Unlock Key and Secure Remote Password.** These are used to create a new personal keyset, encrypted authorisation, and public key. For each vault the service account has access to, the vault Key will be encrypted with the personal keyset. More info [here](https://developer.1password.com/docs/service-accounts/security/#:~:text=When%20you%20create%20a%20service,encrypted%20authorization%2C%20and%20public%20key).
> [!faq]- How does **service account token** looks like?
>
> It's just a JWT (JSON Web Token) used for accessing an API.
>
> `ops_` is a prefix to help static code analysers identify accidental credential exposure.
> #### Encrypted:
> ```text
> ops_eyJzaWduSW5BZGRyZXNzIjoibXkuMXBhc3N3b3JkLmNvbSIsInVzZXJBdXRoIjp7Im1ldGhvZCI6IlNSUGctNDA5NiIsImFsZyI6IlBCRVMyZy1IUzI1NiIsIml0ZXJhdGlvbnMiOjY1MDAwMCwic2FsdCI6IllWYnV5LTZkazZpZGRYNGNMMS1qVVEifSwiZW1haWwiOiJyNmppdGN3bmRiN29vQDFwYXNzd29yZHNlcnZpY2VhY2NvdW50cy5jb20iLCJzcnBYIjoiZjIyZjRmZWQyYTI2MjcxM2ZhZWUxNzczYTEwOWI2MTFjMmE5YmU1ZTkxMjFhOTYzMDNmZTgwZGU5ODlkYjc4MSIsIm11ayI6eyJhbGciOiJBMjU2R0NNIiwiZXh0Ijp0cnVlLCJrIjoiRnVocnM5ZXVoYVlsUlZpQ05CX2x1bUZFUWRfSVl2dVZYYUJvQ3ZLbjVlNCIsImtleV9vcHMiOlsiZW5jcnlwdCIsImRlY3J5cHQiXSwia3R5Ijoib2N0Iiwia2lkIjoibXAifSwic2VjcmV0S2V5IjoiQTMtRlpBSks4LVZRRFpUQy1RNjVYRS05RTQ2Mi1MTVRDSC1WQUVGTiIsInRocm90dGxlU2VjcmV0Ijp7InNlZWQiOiIwZmExYTE0ZWVkM2IzZGZmN2I4ZDk3NDk5MDM1Y2M1M2IxYzY0YjFiNWI2ZjhmMzQ0NTgwYzViMDJiNDhiM2VjIiwidXVpZCI6IkxYSlRUN0dMWkJDNEJNUVoyVkFKSUQ2UlJBIn0sImRldmljZVV1aWQiOiIzcjJtNWFlM3JsYWlwbWZzcDd4ZXhmM296YSJ9
> ```
> #### Decrypted
> ```json
> {
> "signInAddress": "my.1password.com",
> "userAuth": {
> "method": "SRPg-4096",
> "alg": "PBES2g-HS256",
> "iterations": 650000,
> "salt": "YVbuy-6dk6iddX4cL1-jUQ"
> },
> "email": "
[email protected]",
> "srpX": "f22f4fed2a262713faee1773a109b611c2a9be5e9121a96303fe80de989db781",
> "muk": {
> "alg": "A256GCM",
> "ext": true,
> "k": "Fuhrs9euhaYlRViCNB_lumFEQd_IYvuVXaBoCvKn5e4",
> "key_ops": [
> "encrypt",
> "decrypt"
> ],
> "kty": "oct",
> "kid": "mp"
> },
> "secretKey": "A3-FZAJK8-VQDZTC-Q65XE-9E462-LMTCH-VAEFN",
> "throttleSecret": {
> "seed": "0fa1a14eed3b3dff7b8d97499035cc53b1c64b1b5b6f8f344580c5b02b48b3ec",
> "uuid": "LXJTT7GLZBC4BMQZ2VAJID6RRA"
> },
> "deviceUuid": "3r2m5ae3rlaipmfsp7xexf3oza"
> }
> ```
> Don't try to use it, it's for already deleted throwaway account 🙂.
### References
- [1Password Security Design](https://1passwordstatic.com/files/security/1password-white-paper.pdf)
- [About the 1Password security model](https://support.1password.com/1password-security/)
- [Security of Touch ID or Apple Watch to unlock 1Password for Mac](https://support.1password.com/touch-id-apple-watch-security-mac/)
- [About your Secret Key | 1Password](https://support.1password.com/secret-key-security/)
- [1password | Darth Null](https://darthnull.org/series/1password/)
## CLI
### Install
```bash
brew install --cask 1password/tap/1password-cli
```
### Usage
#### `op read` command
The `op read` command is used to retrieve an item or object from a 1Password vault. The item could be a login, a secure note, a credit card, or any other kind of secure data that you've stored in 1Password.
```shell
curl -sS -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $(op read "op://Personal/repo-token/token")" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/user/repos?per_page=100&page=1" | jq '.[] | "\(.full_name)"'
```
#### `op inject` command
#docker
The `op inject` command allows you to inject 1Password secrets into a script or a command-line application securely. It essentially replaces placeholders in your scripts with the actual secrets, so you don't have to hard-code them.
`.env.1p` file:
```shell
MINIO_ROOT_USER="op://Personal/docker-minio/minio.env.MINIO_ROOT_USER"
MINIO_ROOT_PASSWORD="op://Personal/docker-minio/minio.env.MINIO_ROOT_PASSWORD"
```
`docker-compose.yaml`:
```yaml
# More info at https://github.com/minio/minio/blob/master/docs/orchestration/docker-compose/docker-compose.yaml
version: '3'
services:
minio:
container_name: minio
image: minio/minio:RELEASE.2023-09-16T01-01-47Z
restart: unless-stopped
network_mode: host
command: minio server /data
volumes:
- ./minio/data:/data
- ./minio/config:/root/.minio:ro
environment:
MINIO_CONSOLE_ADDRESS: ":9001"
```
Generate `.env` file:
```shell
op inject -i .env.1p -o .env
# to overwrite output file use
op inject -f -i .env.1p -o .env
```
Running `docker-compose` will automatically pick up `.env` if's stored on the same level.
```shell
docker-compose up
```
If it's done inside a git repository, don't forget to add `.env` to `.gitignore`.
#### `op run` command
The `op run` command is used to pass secrets as environment variables to a process.
`dump.sh`:
```shell
#!/usr/bin/env bash
echo "$TOKEN" | tee /tmp/token
```
```shell-session
$ export TOKEN="op://Personal/some-login/password"
$ op run -- ./dump.sh
<concealed by 1Password>
$ cat /tmp/token
iwuZm2ECnGsDKFA3XgZJ
$ op run --no-masking -- ./dump.sh
iwuZm2ECnGsDKFA3XgZJ
$ cat /tmp/token
iwuZm2ECnGsDKFA3XgZJ
```
**Secret path** can be generated by:
1. Clicking on the arrow in field
2. Copying Secret Reference
> [!faq] How does masking work under the hood?
>
> `op run` spawns a child process, and its stdout and stderr are redirected to the parent process. `op run` knows our 'secret', so it can prevent it from leaking by concealing it.
>
> ![[Pasted image 20230925084237.png|Process structure for op run|300]]
### Shell integration
1Password integrates well with many shell programs. I had good experience with [vault integration](https://developer.1password.com/docs/cli/shell-plugins/hashicorp-vault/) for HashiCorp Vault.
> [!faq] How does it work internally?
>
> Shell integration works by creating alias to run the specified program, in our example `vault`:
> ```shell-session
> $ which vault
> vault: aliased to op plugin run -- vault
> ```
### References
- [Load secrets into scripts | 1Password Developer](https://developer.1password.com/docs/cli/secrets-scripts)
## SSH
IMHO **the killer feature** compared to other password managers. It's even [more secure](https://developer.1password.com/docs/ssh/agent/security) than default OpenSSH agent, especially if you lock your vault after 1 minute of inactivity.
List available keys (only their names are available to public, usage of private key is enforced)
```shell-session
$ export SSH_AUTH_SOCK=~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock
$ ssh-add -l
256 SHA256:J+NjzpU+iBW865LPWAtt87y667DOlBmHVT+MNAtH5ao id_ed25519 (ED25519)
4096 SHA256:naYTBPzN1pQ0mqNrH9GK27hIbkEK1ClEri2MjckJgjo id_rsa_aws (RSA)
3072 SHA256:p4P7CGol1yi0JAxymvVS4ScsAYRkRjRIMgNpy2wbsLE id_rsa_azure (RSA)
```
> [!info]
>
> By default, all [eligible](https://developer.1password.com/docs/ssh/agent/#eligible-keys) private keys are available for processes to see. You can overwrite this functionality, for example, to expose only some of them. See [here](https://developer.1password.com/docs/ssh/agent/config/#add-individual-keys) for more info.
SSH client by default tries all keys in order… If we have many keys it will usually fail after 6th failed attempt. To avoid that we can use `IdentityFile` to point to the **public key** of corresponding **private key** (Usually `IdentityFile` points to private keys but we can also use public key and it will try to find corresponding key in ssh agent on the 1st try).
Example `~/.ssh/config`:
```text
Host server1.example.com 10.0.10.10
User root
IdentityFile ~/.ssh/id_ed25519.pub
```
> [!warning]
>
> Some SSH clients don't support specifying public keys in `IdentityFile`. See [SSH client compatibility](https://developer.1password.com/docs/ssh/agent/compatibility/).
![[Pasted image 20230924071652.png|Popup if some application requests access to the private key on SSH_AUTH_SOCK path]]
### Fix for JetBrain's IDEs
1. Settings -> Advanced -> Search for SSH
2. Set parser from Legacy to OpenSSH
### References
- [1Password for SSH & Git | 1Password Developer](https://developer.1password.com/docs/ssh)
## Passkeys
The https://passkeys.directory/ is a curated list of websites that have passkeys enabled.
> [!danger] There is no way to export/backup the private keys of passkeys [at the moment](https://support.1password.com/save-use-passkeys/#get-help), although there is a [draft](https://blog.1password.com/fido-alliance-import-export-passkeys-draft-specs/) that should enable it.
### References
- [RFC 6631](https://datatracker.ietf.org/doc/html/rfc6631)
- [About the security of passkeys](https://support.apple.com/en-us/102195)
- [How do passkeys work?](https://www.passkeys.io/technical-details)
## Sharing
### Sharing options
One interesting option is an ability to view the secret **only once**.
![[Pasted image 20230924072139.png|Sharing options|400]]
> [!faq] How come that sending link in iMessage, Messenger with "rich preview" doesn't count as view? ![[Pasted image 20231007124956.png|Rich preview on iMessage for Shared secret with single view only|200]]
>
> To count as a view, it needs to be viewed with ==Javascript ON==. To get a [[HTML - Rich previews|rich preview]], all we need is to do simple GET request and then to parse some tags to be able to render it.
>
> Example of HTML tags for 1Password:
> ```html
> <meta property="og:type" content="website">
> <meta property="og:site_name" content="1Password">
> <meta property="og:title" content="I’m sharing an item with you using 1Password">
> <meta property="og:description"
> content="A password manager, digital vault, form filler and secure digital wallet. 1Password remembers all your passwords for you to help keep account information safe.">
> <meta property="og:image" content="https://share.1password.com/static/img/share-image-v1.png">
> <meta property="og:image:secure_url" content="https://share.1password.com/static/img/share-image-v1.png">
> <meta name="twitter:card" content="summary_large_image">
> <meta name="twitter:site" content="@1Password">
> <meta name="twitter:title" content="I’m sharing an item with you using 1Password">
> <meta name="twitter:description"
> content="A password manager, digital vault, form filler and secure digital wallet. 1Password remembers all your passwords for you to help keep account information safe.">
> <meta name="twitter:image" content="https://share.1password.com/static/img/share-image-v1.png">
> ```
### Sharing history
To view the sharing history (including expiration and whether it was viewed), we need to go to 1Password on the website:
![[Pasted image 20231122102409.png|Sharing history|400]]
## Integrations
### Github Actions
1. Create **CI/CD** Vault
2. Create Service Account with **read-only** access to newly created Vault https://my.1password.com/integrations/infrastructure-secrets?type=github-actions
3. Create `.github/workflows/1password-test.yaml`:
```yaml
on: push
jobs:
test-1password:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure 1Password Service Account
uses: 1password/load-secrets-action/configure@v1
with:
service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
- name: Load secret
uses: 1password/load-secrets-action@v1
env:
SECRET: op://3i6keyjphzyzd6cfw7rgcwqzhy/secret-token/credential
- name: Show default environment variables
run: |
echo "The job_id is: $GITHUB_JOB" # reference the default environment variables
echo "The id of this action is: $GITHUB_ACTION" # reference the default environment variables
echo "The run id is: $GITHUB_RUN_ID"
echo "The GitHub Actor's username is: $GITHUB_ACTOR"
echo "GitHub SHA: $GITHUB_SHA"
echo "secret: $SECRET"
```
#### References
- [Load secrets from 1Password into GitHub Actions | 1Password Developer](https://developer.1password.com/docs/ci-cd/github-actions/)
### Kubernetes
#k8s/operators
There are currently 2 methods of retrieving the secrets:
1. Generating Secret objects - IMHO the only correct way:
- this way it can be fully [[GitOps]] and audited easily with Pull Requests and [[ArgoCD]]
- can be bundled together with application in "one package"
1. Mutating webhook to inject ENV variables
#### Method 1
- Certificates/Private keys should be uploaded to 1Password as documents - https://github.com/1Password/onepassword-operator/issues/82, https://github.com/1Password/onepassword-operator/pull/80
- Regular secrets
```yaml
# This CRD will generate Secret with name <item_name> and populated with all fields from Secret
apiVersion: onepassword.com/v1
kind: OnePasswordItem
metadata:
name: <item_name> #this name will also be used for naming the generated kubernetes secret
spec:
itemPath: "vaults/<vault_id_or_title>/items/<item_id_or_title>"
```
### References
- Method 1
- https://github.com/1Password/onepassword-operator/blob/main/USAGEGUIDE.md
- https://github.com/1Password/onepassword-operator
- Method 2
- https://developer.1password.com/docs/connect/k8s-injector/
## Labs
Beta testing new functionality on stable builds can be enabled on https://1password.community/categories/labs.
## Setup
1. Download iPassword 8 (not version 7 from App Store)
- version 8 uses accessibility features for clever autofill in operating system and apps that use them can't go to App Store
2. Enable accessibilty features ([How to](https://support.1password.com/mac-universal-autofill/#set-up-universal-autofill))
3. General tab settings ![[Pasted image 20231002115252.png|General tab settings|500]]
4. Security tab settings ![[Pasted image 20230926234439.png|Security tab settings|500]]
5. Developer tab settings ![[Pasted image 20230927005534.png|Developer tab settings|500]]
## Hacking
The vault's data is stored in a single sqlite database. It can be easily peeked inside on macOS but it is mostly encrypted. 1Password server infrastructure synchronises this database (probably just updates, not full copy on every change) with every device you have installed 1Password on.
```shell
# Copy 1Password database to avoid modifying the real one
sudo cp "/Users/$USER/Library/Group Containers/2BUA8C4S2C.com.1password/Library/Application Support/1Password/Data/1password.sqlite" "$HOME/"
sudo chown "$USER":staff "$HOME/1password.sqlite"
# This command shows the content inside
sqlite3 1password.sqlite .dump
```