Signed URLs Commands¶
The site signed-urls command group provides functionality to create and verify cryptographically signed URLs for secure, time-limited file access.
Overview¶
Signed URLs allow you to: - Grant temporary access to specific files without authentication - Control access duration and permissions - Share files securely via simple URLs - Revoke access by changing the master token - Invalidate all existing signed URLs if the master token is rotated or revoked
What are Signed URLs?¶
A signed URL is a regular URL with cryptographic signature parameters added: - Contains file path, expiration time, and permissions - Signed with the site's master token - Can be shared freely and accessed without further authentication - Automatically expires after specified duration - Cannot be modified without invalidating the signature
Example:
Global Flags¶
--debug,-d,--verbose- Show debug information--insecure,-k- Skip TLS certificate verification--force,-f,-y,--yes- Force operations without prompting--output,-o- Output format:json,yaml, ortable
Commands¶
sitesctl site signed-urls create¶
Create a signed URL for a file or directory.
Usage:
Flags:
--url(required) - Full URL to sign- Must be complete URL including protocol and domain
-
Should point to a file or directory on your site
-
--duration- Token lifetime in seconds - Default:
86400(24 hours) -
After this period, the URL becomes invalid
-
--permission- Access permission level - Values:
r(read-only) orrw(read/write) - Default:
r - Note: Write permission via signed URL depends on server configuration
Examples:
# Create read-only signed URL (24 hour default)
sitesctl site --space myspace --name mysite \
signed-urls create \
--url https://sites.ecmwf.int/myspace/mysite/data/file.txt
# Create signed URL for 1 hour
sitesctl site --space myspace --name mysite \
signed-urls create \
--url https://sites.ecmwf.int/myspace/mysite/reports/report.pdf \
--duration 3600
# Create signed URL for 7 days
sitesctl site --space myspace --name mysite \
signed-urls create \
--url https://sites.ecmwf.int/myspace/mysite/archive/ \
--duration 604800
# Create with read/write permission
sitesctl site --space myspace --name mysite \
signed-urls create \
--url https://sites.ecmwf.int/myspace/mysite/upload/data.csv \
--permission rw \
--duration 3600
# Save signed URL to variable
signed_url=$(sitesctl site --space myspace --name mysite \
signed-urls create \
--url https://sites.ecmwf.int/myspace/mysite/file.txt \
--output json | jq -r '.signed_url')
Common Duration Values:
| Duration | Seconds | Use Case |
|---|---|---|
| 1 hour | 3600 | Quick file sharing |
| 6 hours | 21600 | Work session |
| 24 hours | 86400 | Daily access (default) |
| 7 days | 604800 | Weekly sharing |
| 30 days | 2592000 | Long-term access |
Output: - Original URL - Signed URL (with signature and expiration parameters) - Expiration timestamp - Permission level
Use Cases: - Share files with external users - Embed in emails or documents - Temporary public access - Time-limited downloads - Integration with external systems
sitesctl site signed-urls verify¶
Verify a signed URL and check its validity.
Usage:
Flags:
- --url (required) - Signed URL to verify
Examples:
# Verify a signed URL
sitesctl site --space myspace --name mysite \
signed-urls verify \
--url "https://sites.ecmwf.int/myspace/mysite/file.txt?signature=abc&expires=123"
# Verify with JSON output
sitesctl site --space myspace --name mysite \
signed-urls verify \
--url "https://sites.ecmwf.int/myspace/mysite/file.txt?signature=abc&expires=123" \
--output json
What it does: - Validates the signature - Checks expiration time - Confirms the URL hasn't been tampered with - Returns validity status
Output: - Validity status (valid/invalid) - Expiration date/time (if valid) - Error message (if invalid) - Permission level
Use Cases: - Check URL before sharing - Verify URL hasn't expired - Debug access issues - Audit URL validity
How Signed URLs Work¶
Creation Process¶
- Input: Original URL + duration + permissions
- Calculation:
- Expiration timestamp = current time + duration
- Signature = HMAC(URL + expires + permission, master_token)
- Output: URL + signature + expiration parameters
Verification Process¶
- Parse: Extract URL, signature, expiration from signed URL
- Check Expiration: Compare expiration timestamp with current time
- Verify Signature: Recalculate signature and compare with provided signature
- Result: Valid if signature matches and not expired
Security Properties¶
- Integrity: URL cannot be modified without invalidating signature
- Expiration: Automatically becomes invalid after duration
- Non-transferable: Tied to specific file path
- Revocable: Rotating master token invalidates all signed URLs
- Master token dependency: Rotating or revoking the master token invalidates all existing signed URLs
Comparison: Signed URLs vs HTTP Access Tokens¶
| Feature | Signed URLs | HTTP Access Tokens |
|---|---|---|
| Scope | Single file/directory | Entire site |
| Authentication | No (embedded in URL) | Yes (in headers/params) |
| Sharing | Very easy (just share URL) | Moderate (share token + instructions) |
| Expiration | Per-URL | Per-token |
| Use in Browser | Direct access | Requires parameter or extension |
| Granularity | Per-file | Site-wide |
| Best For | File sharing, embeddings | API access, automation |
When to use Signed URLs: - Sharing specific files with non-technical users - Embedding files in web pages or documents - Temporary public access to specific resources - Simple click-to-download scenarios
When to use HTTP Access Tokens: - API integrations - Automated content management - Multiple file operations - Complex workflows
Common Workflows¶
Share File via Email¶
#!/bin/bash
# Create signed URL and send via email
space="myspace"
name="mysite"
file_path="reports/monthly-report.pdf"
recipient="colleague@example.com"
# Create 7-day signed URL
signed_url=$(sitesctl site --space "$space" --name "$name" \
signed-urls create \
--url "https://sites.ecmwf.int/${space}/${name}/${file_path}" \
--duration 604800 \
--output json | jq -r '.signed_url')
# Send email
cat <<EOF | mail -s "Monthly Report" "$recipient"
Hi,
Please find the monthly report here:
$signed_url
This link expires in 7 days.
Best regards
EOF
echo "Signed URL sent to $recipient"
Embed in Web Page¶
#!/bin/bash
# Generate HTML with signed URL
space="myspace"
name="mysite"
image_path="images/chart.png"
# Create 30-day signed URL
signed_url=$(sitesctl site --space "$space" --name "$name" \
signed-urls create \
--url "https://sites.ecmwf.int/${space}/${name}/${image_path}" \
--duration 2592000 \
--output json | jq -r '.signed_url')
# Generate HTML
cat <<EOF > chart.html
<!DOCTYPE html>
<html>
<head><title>Chart</title></head>
<body>
<h1>Data Chart</h1>
<img src="$signed_url" alt="Chart">
</body>
</html>
EOF
echo "HTML file generated with signed URL"
Batch Generate Signed URLs¶
#!/bin/bash
# Create signed URLs for multiple files
space="myspace"
name="mysite"
base_url="https://sites.ecmwf.int/${space}/${name}"
files=(
"data/file1.csv"
"data/file2.csv"
"data/file3.csv"
)
echo "Generating signed URLs..."
for file in "${files[@]}"; do
signed_url=$(sitesctl site --space "$space" --name "$name" \
signed-urls create \
--url "${base_url}/${file}" \
--duration 86400 \
--output json | jq -r '.signed_url')
echo "$file -> $signed_url"
done > signed_urls.txt
echo "Signed URLs saved to signed_urls.txt"
Verify Before Sharing¶
#!/bin/bash
# Create and verify signed URL before sharing
space="myspace"
name="mysite"
file_url="https://sites.ecmwf.int/${space}/${name}/data/report.pdf"
# Create signed URL
signed_url=$(sitesctl site --space "$space" --name "$name" \
signed-urls create \
--url "$file_url" \
--duration 604800 \
--output json | jq -r '.signed_url')
echo "Signed URL created: $signed_url"
# Verify it
echo "Verifying..."
sitesctl site --space "$space" --name "$name" \
signed-urls verify --url "$signed_url"
if [ $? -eq 0 ]; then
echo "URL verified successfully!"
echo "Safe to share: $signed_url"
else
echo "URL verification failed!"
exit 1
fi
Time-Limited Public Gallery¶
#!/bin/bash
# Create gallery of images with signed URLs
space="myspace"
name="mysite"
base_url="https://sites.ecmwf.int/${space}/${name}"
duration=604800 # 7 days
# Get list of images
images=$(sitesctl site --space "$space" --name "$name" \
content list --path /gallery --match "*.jpg" --output json | \
jq -r '.[].name')
# Generate HTML gallery
cat <<EOF > gallery.html
<!DOCTYPE html>
<html>
<head>
<title>Image Gallery</title>
<style>
.gallery { display: flex; flex-wrap: wrap; gap: 10px; }
.gallery img { width: 300px; height: auto; }
</style>
</head>
<body>
<h1>Image Gallery (Links expire in 7 days)</h1>
<div class="gallery">
EOF
# Add each image with signed URL
for image in $images; do
signed_url=$(sitesctl site --space "$space" --name "$name" \
signed-urls create \
--url "${base_url}/gallery/${image}" \
--duration "$duration" \
--output json | jq -r '.signed_url')
echo " <img src=\"$signed_url\" alt=\"$image\">" >> gallery.html
done
cat <<EOF >> gallery.html
</div>
</body>
</html>
EOF
echo "Gallery generated: gallery.html"
Security Considerations¶
Best Practices¶
- Minimize Duration
- Use shortest practical duration
- Default to 24 hours unless longer needed
-
Regenerate for extended access
-
Use Read-Only Permission
- Default to
rpermission - Only use
rwwhen absolutely necessary -
Understand write implications
-
Monitor Access
- Track which URLs you create
- Log URL generation with identifiers
-
Review access logs regularly
-
Rotate Master Token
- Rotating master token invalidates all signed URLs
- Use as emergency revocation mechanism
- Plan URL regeneration strategy
Security Risks¶
URL Exposure: - Signed URLs contain authentication in the URL itself - Can be logged by proxies, browsers, servers - Can be shared further by recipients - Consider for sensitive data
No Usage Limits: - Valid signed URL can be used repeatedly - No download count limit - Consider for high-value content
URL Sharing: - Recipient can share the URL - No way to track secondary sharing - URL remains valid until expiration
Mitigation Strategies¶
- Short Durations: Minimize window of exposure
- File Sensitivity: Use for less sensitive content
- Access Logging: Monitor who accesses URLs
- Token Rotation: Emergency revocation via master token rotation
- Alternative Methods: Consider HTTP access tokens for sensitive operations
Troubleshooting¶
URL Expired¶
Problem: Signed URL no longer works
Solutions:
- Check expiration with signed-urls verify
- Generate new signed URL with appropriate duration
- Consider longer duration if frequently needed
Invalid Signature¶
Problem: URL reports invalid signature
Solutions: - Verify URL wasn't modified - Check if master token was rotated - Regenerate the signed URL
Access Denied¶
Problem: Valid signed URL but access denied
Solutions:
- Verify the file exists: sitesctl site ... content list
- Check file permissions on server
- Ensure site is not archived
- Verify site health
URL Not Working in Browser¶
Problem: URL doesn't load in web browser
Solutions: - URL-encode special characters - Verify URL is complete (includes signature params) - Check if site is accessible - Test with curl first
curl Examples¶
Download with Signed URL¶
# Simple download
curl -O "https://sites.ecmwf.int/space/site/file.txt?signature=...&expires=..."
# Download with custom filename
curl -o myfile.txt "https://sites.ecmwf.int/space/site/file.txt?signature=...&expires=..."
# Follow redirects
curl -L -O "https://sites.ecmwf.int/space/site/file.txt?signature=...&expires=..."
Upload with Signed URL (rw permission)¶
# Upload file
curl -X PUT \
--data-binary @localfile.txt \
"https://sites.ecmwf.int/space/site/path/file.txt?signature=...&expires=..."
Check URL Validity with curl¶
# HEAD request to check accessibility
curl -I "https://sites.ecmwf.int/space/site/file.txt?signature=...&expires=..."
# Should return 200 OK if valid
Integration Examples¶
Python Script¶
import subprocess
import json
import requests
def create_signed_url(space, name, file_path, duration=86400):
"""Create a signed URL using sitesctl"""
url = f"https://sites.ecmwf.int/{space}/{name}/{file_path}"
cmd = [
"sitesctl", "site",
"--space", space,
"--name", name,
"signed-urls", "create",
"--url", url,
"--duration", str(duration),
"--output", "json"
]
result = subprocess.run(cmd, capture_output=True, text=True)
data = json.loads(result.stdout)
return data['signed_url']
# Usage
signed_url = create_signed_url("myspace", "mysite", "data/file.csv")
print(f"Signed URL: {signed_url}")
# Download the file
response = requests.get(signed_url)
with open("downloaded.csv", "wb") as f:
f.write(response.content)
Node.js Script¶
const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);
async function createSignedUrl(space, name, filePath, duration = 86400) {
const url = `https://sites.ecmwf.int/${space}/${name}/${filePath}`;
const cmd = `sitesctl site --space ${space} --name ${name} ` +
`signed-urls create --url ${url} --duration ${duration} --output json`;
const { stdout } = await execPromise(cmd);
const data = JSON.parse(stdout);
return data.signed_url;
}
// Usage
createSignedUrl('myspace', 'mysite', 'data/file.csv')
.then(signedUrl => console.log(`Signed URL: ${signedUrl}`))
.catch(err => console.error('Error:', err));
See Also¶
- Site Token Management - Alternative authentication method
- Site Content Commands - Managing the files you're sharing
- Authentication Commands - CLI authentication setup