Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit a9c94e9

Browse files
committed
feat: [#28] add secure token storage for Hetzner Cloud API
Implement secure file-based storage for Hetzner Cloud API tokens following the same pattern established for Hetzner DNS tokens. **Infrastructure Changes:** - Enhanced Hetzner provider script to auto-detect tokens from secure storage - Added fallback to environment variables for backward compatibility - Improved error messages with setup instructions for both methods **Documentation Updates:** - Added Hetzner Cloud token secure storage section to DNS setup guide - Updated Hetzner Cloud setup guide with secure storage instructions - Enhanced help text and setup instructions in provider scripts **Security Benefits:** - Tokens stored in ~/.config/hetzner/cloud_api_token with 600 permissions - Reduced exposure in environment variables and command history - Consistent approach across all Hetzner API integrations **User Experience:** - Automatic token detection - no environment variables needed - Clear setup instructions for both storage methods - Backward compatible with existing HETZNER_TOKEN workflows All infrastructure tests pass. Successfully validated with production infrastructure destruction using secure token storage.
1 parent 51a986c commit a9c94e9

File tree

3 files changed

+142
-14
lines changed

3 files changed

+142
-14
lines changed

docs/guides/hetzner-cloud-setup-guide.md

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,53 @@ This guide explains how to set up and use the Hetzner Cloud provider with the To
2323
5. Set permissions to **Read & Write**
2424
6. Copy the generated token (64 characters)
2525

26+
## Step 2.5: Secure Token Storage (Recommended)
27+
28+
For enhanced security, store your Hetzner Cloud API token using secure file storage
29+
instead of environment variables:
30+
31+
### Option 1: Secure Storage (Recommended)
32+
33+
```bash
34+
# Create secure storage directory
35+
mkdir -p ~/.config/hetzner
36+
chmod 700 ~/.config/hetzner
37+
38+
# Store the Hetzner Cloud API token (replace YOUR_TOKEN_HERE with actual token)
39+
echo "YOUR_TOKEN_HERE" > ~/.config/hetzner/cloud_api_token
40+
chmod 600 ~/.config/hetzner/cloud_api_token
41+
42+
# Verify storage
43+
ls -la ~/.config/hetzner/
44+
# Should show: -rw------- 1 user user 65 date time cloud_api_token
45+
```
46+
47+
### Test Token Storage
48+
49+
```bash
50+
# Test that token can be loaded from storage
51+
CLOUD_TOKEN=$(cat ~/.config/hetzner/cloud_api_token)
52+
echo "Token length: ${#CLOUD_TOKEN} characters"
53+
# Should show: Token length: 64 characters
54+
55+
# Test API access
56+
curl -H "Authorization: Bearer $CLOUD_TOKEN" \
57+
"https://api.hetzner.cloud/v1/servers" | jq
58+
# Expected output: {"servers": []}
59+
```
60+
61+
### Option 2: Environment Variable (Fallback)
62+
63+
If you prefer environment variables, you can still use the traditional approach:
64+
65+
```bash
66+
export HETZNER_TOKEN=your_64_character_token_here
67+
```
68+
69+
> **Note**: The infrastructure scripts will automatically detect tokens from secure
70+
> storage first, then fall back to environment variables. Secure storage is
71+
> recommended for production use.
72+
2673
## Step 3: Configure Provider
2774

2875
1. Copy the provider configuration template:
@@ -79,31 +126,29 @@ For production deployment, create a production environment:
79126

80127
## Step 5: Deploy Infrastructure
81128

82-
1. Export your Hetzner token:
83-
84-
```bash
85-
export HETZNER_TOKEN=your_64_character_token_here
86-
```
129+
The infrastructure scripts will automatically detect your Hetzner token from secure
130+
The infrastructure scripts will automatically detect your Hetzner token from secure
131+
storage (`~/.config/hetzner/cloud_api_token`) or from environment variables.
87132

88-
2. Initialize Terraform:
133+
1. Initialize Terraform:
89134

90135
```bash
91136
make infra-init ENVIRONMENT=production PROVIDER=hetzner
92137
```
93138

94-
3. Plan the deployment:
139+
2. Plan the deployment:
95140

96141
```bash
97142
make infra-plan ENVIRONMENT=production PROVIDER=hetzner
98143
```
99144

100-
4. Apply the infrastructure:
145+
3. Apply the infrastructure:
101146

102147
```bash
103148
make infra-apply ENVIRONMENT=production PROVIDER=hetzner
104149
```
105150

106-
5. Deploy the application:
151+
4. Deploy the application:
107152

108153
```bash
109154
make app-deploy ENVIRONMENT=production

docs/guides/hetzner-dns-setup-guide.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,62 @@ curl -H "Auth-API-Token: $DNS_TOKEN" \
8989
# Expected output: {"zones": []} (empty array for new accounts)
9090
```
9191

92+
## 🔑 Step 1.5: Hetzner Cloud API Token (Infrastructure Integration)
93+
94+
For complete Hetzner integration, you'll also need a Hetzner Cloud API token for
95+
infrastructure provisioning. This is separate from the DNS API token but can be
96+
stored using the same secure method.
97+
98+
### 1.5.1 Generate Hetzner Cloud API Token
99+
100+
1. Go to [Hetzner Cloud Console](https://console.hetzner.cloud/)
101+
2. Navigate to your project
102+
3. Go to **"Security" → "API Tokens"**
103+
4. Click **"Generate API token"**
104+
5. Provide a descriptive name:
105+
106+
```text
107+
Name: torrust-infrastructure-automation
108+
Description: Infrastructure automation for Torrust Tracker Demo
109+
Permissions: Read & Write (required for creating/destroying servers)
110+
```
111+
112+
6. Click **"Generate token"**
113+
7. **Important**: Copy and save the token immediately
114+
115+
### 1.5.2 Secure Cloud Token Storage
116+
117+
Store the Hetzner Cloud API token alongside the DNS token:
118+
119+
```bash
120+
# Store the Hetzner Cloud API token (replace YOUR_CLOUD_TOKEN_HERE with actual token)
121+
echo "YOUR_CLOUD_TOKEN_HERE" > ~/.config/hetzner/cloud_api_token
122+
chmod 600 ~/.config/hetzner/cloud_api_token
123+
124+
# Verify both tokens are stored securely
125+
ls -la ~/.config/hetzner/
126+
# Should show:
127+
# -rw------- 1 user user 65 date time cloud_api_token
128+
# -rw------- 1 user user 65 date time dns_api_token
129+
```
130+
131+
### 1.5.3 Test Cloud API Access
132+
133+
```bash
134+
# Load token from secure storage
135+
CLOUD_TOKEN=$(cat ~/.config/hetzner/cloud_api_token)
136+
137+
# Test API access
138+
curl -H "Authorization: Bearer $CLOUD_TOKEN" \
139+
"https://api.hetzner.cloud/v1/servers" | jq
140+
141+
# Expected output: {"servers": []} (empty array for new accounts)
142+
```
143+
144+
> **Note**: The infrastructure scripts will automatically detect and use the token
145+
> from `~/.config/hetzner/cloud_api_token`. You no longer need to set the
146+
> `HETZNER_TOKEN` environment variable if using secure storage.
147+
92148
## 🌐 Step 2: Create DNS Zone
93149

94150
### 2.1 Create Zone for Your Domain

infrastructure/terraform/providers/hetzner/provider.sh

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,29 @@ provider_validate_prerequisites() {
1919
log_info "Note: CLI is optional, Terraform provider will work without it"
2020
fi
2121

22-
# Validate required environment variables
23-
if [[ -z "${HETZNER_TOKEN:-}" ]]; then
24-
log_error "HETZNER_TOKEN environment variable is required"
22+
# Load Hetzner Cloud API token from secure storage or environment variable
23+
local hetzner_token_file="$HOME/.config/hetzner/cloud_api_token"
24+
25+
if [[ -f "$hetzner_token_file" ]]; then
26+
# Load token from secure storage (preferred method)
27+
HETZNER_TOKEN=$(cat "$hetzner_token_file")
28+
log_info "Loaded Hetzner Cloud API token from secure storage"
29+
elif [[ -n "${HETZNER_TOKEN:-}" ]]; then
30+
# Use token from environment variable (fallback)
31+
log_info "Using Hetzner Cloud API token from environment variable"
32+
else
33+
# No token found
34+
log_error "HETZNER_TOKEN not found in environment or secure storage"
35+
log_error ""
36+
log_error "Option 1 - Secure Storage (Recommended):"
37+
log_error " 1. mkdir -p ~/.config/hetzner"
38+
log_error " 2. echo 'your_token_here' > ~/.config/hetzner/cloud_api_token"
39+
log_error " 3. chmod 600 ~/.config/hetzner/cloud_api_token"
40+
log_error ""
41+
log_error "Option 2 - Environment Variable:"
42+
log_error " export HETZNER_TOKEN=your_token_here"
43+
log_error ""
2544
log_error "Get your token from: https://console.hetzner.cloud/"
26-
log_error "Set it with: export HETZNER_TOKEN=your_token_here"
2745
exit 1
2846
fi
2947

@@ -131,6 +149,12 @@ provider_get_info() {
131149
echo ""
132150
echo "Required variables:"
133151
echo " - HETZNER_TOKEN (Hetzner Cloud API token)"
152+
echo " Option 1 - Secure Storage (Recommended):"
153+
echo " mkdir -p ~/.config/hetzner"
154+
echo " echo 'your_token' > ~/.config/hetzner/cloud_api_token"
155+
echo " chmod 600 ~/.config/hetzner/cloud_api_token"
156+
echo " Option 2 - Environment Variable:"
157+
echo " export HETZNER_TOKEN=your_token_here"
134158
echo ""
135159
echo "Optional variables:"
136160
echo " - HETZNER_SERVER_TYPE (default: cx31 - 2 vCPU, 8GB RAM, 80GB SSD)"
@@ -155,7 +179,10 @@ provider_get_info() {
155179
echo "Setup instructions:"
156180
echo " 1. Create Hetzner Cloud account: https://console.hetzner.cloud/"
157181
echo " 2. Generate API token: Project → Security → API Tokens"
158-
echo " 3. Export token: export HETZNER_TOKEN=your_token_here"
182+
echo " 3. Secure token storage (recommended):"
183+
echo " mkdir -p ~/.config/hetzner && chmod 700 ~/.config/hetzner"
184+
echo " echo 'your_token_here' > ~/.config/hetzner/cloud_api_token"
185+
echo " chmod 600 ~/.config/hetzner/cloud_api_token"
159186
echo " 4. Deploy: make infra-apply ENVIRONMENT=production PROVIDER=hetzner"
160187
}
161188

0 commit comments

Comments
 (0)