A Kubernetes operator that bridges Hardware Security Module (HSM) data storage with Kubernetes Secrets, providing true secret portability th
1#!/bin/bash
2
3# Bulk operations for HSM secrets
4# Automatically uses kubectl-hsm plugin if available, falls back to REST API
5# Usage: ./bulk-operations.sh [operation] [config-file]
6
7set -e
8
9API_BASE_URL=${API_BASE_URL:-"http://localhost:8090"}
10OPERATION=${1:-"create"}
11CONFIG_FILE=${2:-"bulk-secrets.json"}
12
13# Function to create bulk secrets config if it doesn't exist
14create_sample_config() {
15 cat > "$CONFIG_FILE" <<EOF
16{
17 "secrets": [
18 {
19 "label": "app1-database",
20 "id": 1001,
21 "format": "json",
22 "description": "Database credentials for app1",
23 "tags": {
24 "app": "app1",
25 "environment": "production",
26 "type": "database"
27 },
28 "data": {
29 "database_url": "postgresql://app1:password123@db.example.com:5432/app1",
30 "username": "app1",
31 "password": "password123"
32 }
33 },
34 {
35 "label": "app2-api-keys",
36 "id": 1002,
37 "format": "json",
38 "description": "External API keys for app2",
39 "tags": {
40 "app": "app2",
41 "environment": "production",
42 "type": "api-keys"
43 },
44 "data": {
45 "stripe_key": "sk_live_example123",
46 "sendgrid_key": "SG.example456",
47 "aws_access_key": "AKIA1234567890"
48 }
49 },
50 {
51 "label": "shared-tls-cert",
52 "id": 1003,
53 "format": "text",
54 "description": "Shared TLS certificate",
55 "tags": {
56 "type": "tls",
57 "scope": "shared",
58 "environment": "production"
59 },
60 "data": {
61 "tls.crt": "-----BEGIN CERTIFICATE-----\\nMIIC...\\n-----END CERTIFICATE-----",
62 "tls.key": "-----BEGIN PRIVATE KEY-----\\nMIIE...\\n-----END PRIVATE KEY-----"
63 }
64 }
65 ]
66}
67EOF
68 echo "📝 Created sample config file: $CONFIG_FILE"
69}
70
71# Function to create a single secret
72create_secret() {
73 local secret_data="$1"
74 local label=$(echo "$secret_data" | jq -r '.label')
75
76 echo " Creating secret: $label"
77
78 # Try using kubectl-hsm first if available, fallback to API
79 if command -v kubectl >/dev/null && kubectl hsm --help >/dev/null 2>&1; then
80 # Convert secret_data to create command format
81 local temp_file=$(mktemp)
82 echo "$secret_data" | jq '.data' > "$temp_file"
83
84 if kubectl hsm create "$label" --from-file="$temp_file" >/dev/null 2>&1; then
85 rm "$temp_file"
86 echo " ✅ Created successfully (kubectl-hsm)"
87 return 0
88 else
89 rm "$temp_file"
90 echo " ⚠️ kubectl-hsm failed, trying API..."
91 fi
92 fi
93
94 # Fallback to API
95 response=$(curl -s -X POST \
96 -H "Content-Type: application/json" \
97 -d "$secret_data" \
98 "$API_BASE_URL/api/v1/hsm/secrets")
99
100 success=$(echo "$response" | jq -r '.success')
101 if [ "$success" = "true" ]; then
102 echo " ✅ Created successfully (API)"
103 return 0
104 else
105 error_message=$(echo "$response" | jq -r '.error.message // "Unknown error"')
106 echo " ❌ Failed: $error_message"
107 return 1
108 fi
109}
110
111# Function to delete a secret
112delete_secret() {
113 local label="$1"
114
115 echo " Deleting secret: $label"
116
117 # Try using kubectl-hsm first if available, fallback to API
118 if command -v kubectl >/dev/null && kubectl hsm --help >/dev/null 2>&1; then
119 if kubectl hsm delete "$label" --force >/dev/null 2>&1; then
120 echo " ✅ Deleted successfully (kubectl-hsm)"
121 return 0
122 else
123 echo " ⚠️ kubectl-hsm failed, trying API..."
124 fi
125 fi
126
127 # Fallback to API
128 response=$(curl -s -X DELETE "$API_BASE_URL/api/v1/hsm/secrets/$label")
129
130 success=$(echo "$response" | jq -r '.success')
131 if [ "$success" = "true" ]; then
132 echo " ✅ Deleted successfully (API)"
133 return 0
134 else
135 error_message=$(echo "$response" | jq -r '.error.message // "Unknown error"')
136 echo " ❌ Failed: $error_message"
137 return 1
138 fi
139}
140
141# Function to get secret info
142get_secret() {
143 local label="$1"
144
145 # Try using kubectl-hsm first if available, fallback to API
146 if command -v kubectl >/dev/null && kubectl hsm --help >/dev/null 2>&1; then
147 if kubectl hsm get "$label" >/dev/null 2>&1; then
148 echo " ✅ $label (available via kubectl-hsm)"
149 return 0
150 fi
151 fi
152
153 # Fallback to API for detailed status
154 response=$(curl -s "$API_BASE_URL/api/v1/hsm/secrets/$label")
155 success=$(echo "$response" | jq -r '.success')
156
157 if [ "$success" = "true" ]; then
158 checksum=$(echo "$response" | jq -r '.data.metadata.checksum[0:8]')
159 replicated=$(echo "$response" | jq -r '.data.metadata.is_replicated')
160 echo " ✅ $label (checksum: $checksum, replicated: $replicated)"
161 return 0
162 else
163 echo " ❌ $label (not found or error)"
164 return 1
165 fi
166}
167
168echo "🔄 HSM Secrets Bulk Operations"
169echo "Operation: $OPERATION"
170echo "Config File: $CONFIG_FILE"
171echo "API Base URL: $API_BASE_URL"
172echo ""
173
174# Check if config file exists
175if [ ! -f "$CONFIG_FILE" ]; then
176 echo "⚠️ Config file not found. Creating sample..."
177 create_sample_config
178 echo ""
179fi
180
181# Validate config file
182if ! jq empty "$CONFIG_FILE" 2>/dev/null; then
183 echo "❌ Invalid JSON in config file: $CONFIG_FILE"
184 exit 1
185fi
186
187# Extract secret labels for operations
188secret_labels=$(jq -r '.secrets[].label' "$CONFIG_FILE")
189secret_count=$(echo "$secret_labels" | wc -l)
190
191echo "📊 Found $secret_count secrets in config file"
192echo ""
193
194case "$OPERATION" in
195 "create")
196 echo "🔐 Creating secrets..."
197 success_count=0
198 failure_count=0
199
200 # Process each secret
201 while IFS= read -r secret_json; do
202 if create_secret "$secret_json"; then
203 ((success_count++))
204 else
205 ((failure_count++))
206 fi
207 done < <(jq -c '.secrets[]' "$CONFIG_FILE")
208
209 echo ""
210 echo "📈 Results:"
211 echo " ✅ Successful: $success_count"
212 echo " ❌ Failed: $failure_count"
213 ;;
214
215 "delete")
216 echo "🗑️ Deleting secrets..."
217 success_count=0
218 failure_count=0
219
220 # Delete each secret
221 while IFS= read -r label; do
222 if delete_secret "$label"; then
223 ((success_count++))
224 else
225 ((failure_count++))
226 fi
227 done <<< "$secret_labels"
228
229 echo ""
230 echo "📈 Results:"
231 echo " ✅ Deleted: $success_count"
232 echo " ❌ Failed: $failure_count"
233 ;;
234
235 "status")
236 echo "📊 Checking secret status..."
237 available_count=0
238 missing_count=0
239
240 # Check each secret
241 while IFS= read -r label; do
242 if get_secret "$label"; then
243 ((available_count++))
244 else
245 ((missing_count++))
246 fi
247 done <<< "$secret_labels"
248
249 echo ""
250 echo "📈 Results:"
251 echo " ✅ Available: $available_count"
252 echo " ❌ Missing: $missing_count"
253 ;;
254
255 "backup")
256 echo "💾 Backing up secrets..."
257 backup_file="secrets-backup-$(date +%Y%m%d-%H%M%S).json"
258
259 echo '{"secrets": [' > "$backup_file"
260 first=true
261
262 while IFS= read -r label; do
263 response=$(curl -s "$API_BASE_URL/api/v1/hsm/secrets/$label")
264 success=$(echo "$response" | jq -r '.success')
265
266 if [ "$success" = "true" ]; then
267 if [ "$first" = true ]; then
268 first=false
269 else
270 echo "," >> "$backup_file"
271 fi
272 echo "$response" | jq '.data' >> "$backup_file"
273 echo " ✅ Backed up: $label"
274 else
275 echo " ❌ Failed to backup: $label"
276 fi
277 done <<< "$secret_labels"
278
279 echo ']}' >> "$backup_file"
280 echo ""
281 echo "📁 Backup saved to: $backup_file"
282 ;;
283
284 *)
285 echo "❌ Unknown operation: $OPERATION"
286 echo ""
287 echo "Available operations:"
288 echo " create - Create all secrets from config file"
289 echo " delete - Delete all secrets from config file"
290 echo " status - Check status of all secrets"
291 echo " backup - Backup all secrets to file"
292 echo ""
293 echo "Usage: $0 [operation] [config-file]"
294 exit 1
295 ;;
296esac