Compare commits
18 Commits
8813a4d5ed
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| abbb0842fc | |||
| eac8adbcfa | |||
| d7ad25c4d6 | |||
| 241f70cb22 | |||
| 6822c65a7a | |||
| fb7ec2ac9e | |||
| 76c812794c | |||
| 3b9c295a35 | |||
| 3a068149a7 | |||
| ea7905d7c7 | |||
| d5a715fcfc | |||
| 815278e918 | |||
| 58c31e73bf | |||
| 1a66e46615 | |||
| 93fb89446d | |||
| c8ac9ddebf | |||
| ffdfc2697b | |||
| b698521720 |
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"start-azurite": "shellscript"
|
||||
}
|
||||
}
|
||||
@@ -2,31 +2,31 @@
|
||||
# It uses /etc/hosts entries to route requests to the emulator
|
||||
# Replace "__ACCOUNT_NAME__" with a desired storage account name if needed
|
||||
__ACCOUNT_NAME__.blob.core.windows.net {
|
||||
tls __AZURITE_DIR__/__ACCOUNT_NAME___cert.pem __AZURITE_DIR__/__ACCOUNT_NAME___key.pem
|
||||
tls __AZURITE_STORAGE__/__ACCOUNT_NAME___cert.pem __AZURITE_STORAGE__/__ACCOUNT_NAME___key.pem
|
||||
reverse_proxy https://__ACCOUNT_NAME__.blob.core.windows.net:10000 {
|
||||
transport http {
|
||||
tls
|
||||
tls_trust_pool file __AZURITE_DIR__/ca_cert.pem
|
||||
tls_trust_pool file __AZURITE_STORAGE__/ca_cert.pem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__ACCOUNT_NAME__.queue.core.windows.net {
|
||||
tls __AZURITE_DIR__/__ACCOUNT_NAME___cert.pem __AZURITE_DIR__/__ACCOUNT_NAME___key.pem
|
||||
tls __AZURITE_STORAGE__/__ACCOUNT_NAME___cert.pem __AZURITE_STORAGE__/__ACCOUNT_NAME___key.pem
|
||||
reverse_proxy https://__ACCOUNT_NAME__.queue.core.windows.net:10001 {
|
||||
transport http {
|
||||
tls
|
||||
tls_trust_pool file __AZURITE_DIR__/ca_cert.pem
|
||||
tls_trust_pool file __AZURITE_STORAGE__/ca_cert.pem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__ACCOUNT_NAME__.table.core.windows.net {
|
||||
tls __AZURITE_DIR__/__ACCOUNT_NAME___cert.pem __AZURITE_DIR__/__ACCOUNT_NAME___key.pem
|
||||
tls __AZURITE_STORAGE__/__ACCOUNT_NAME___cert.pem __AZURITE_STORAGE__/__ACCOUNT_NAME___key.pem
|
||||
reverse_proxy https://__ACCOUNT_NAME__.table.core.windows.net:10002 {
|
||||
transport http {
|
||||
tls
|
||||
tls_trust_pool file __AZURITE_DIR__/ca_cert.pem
|
||||
tls_trust_pool file __AZURITE_STORAGE__/ca_cert.pem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
132
README.md
132
README.md
@@ -4,9 +4,13 @@ This is a simple guide that will help you set up and run the Azure Storage Emula
|
||||
|
||||
Review the [Documentation](#reference) for more details on how to use the emulator and its features. This document covers a scenario where you want to run the emulator as close to the real Azure Storage service as possible, which means using triple HTTPS endpoints and OAuth simulation.
|
||||
|
||||
## Docker Installation
|
||||
## Installation
|
||||
|
||||
To run the Azure Storage Emulator in a Docker container, follow these steps:
|
||||
You can install and use the emulator in a few different ways, depending on your preferences and environment. The recommended way is to use a container runtime or Kubernetes, but you can also install it natively using Node.js.
|
||||
|
||||
### Using a container runtime
|
||||
|
||||
To run the Azure Storage Emulator in a container, follow these steps:
|
||||
|
||||
1. Ensure that a container runtime is installed. This repository supports both Docker and Apple `container` command.
|
||||
|
||||
@@ -19,12 +23,43 @@ To run the Azure Storage Emulator in a Docker container, follow these steps:
|
||||
3. Run the emulator container:
|
||||
|
||||
```bash
|
||||
./run.sh
|
||||
./start-azurite
|
||||
```
|
||||
|
||||
## Native Installation
|
||||
You can also use the included example `compose.yaml` file for running it using `docker compose` (or any other compose compatible CLI).
|
||||
|
||||
To install the Azure Storage Emulator natively on your machine, ensure you have Node.js and npm installed, and follow these steps:
|
||||
### Using Kubernetes
|
||||
|
||||
Use the example manifest `azurite-deployment.yaml`.
|
||||
|
||||
1. Create the required Secret from your local env file:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic azurite-accounts \
|
||||
--from-env-file="$HOME/.azurite/accounts.env"
|
||||
```
|
||||
|
||||
2. Deploy the manifest:
|
||||
|
||||
```bash
|
||||
kubectl apply -f azurite-deployment.yaml
|
||||
```
|
||||
|
||||
3. Get the Kubernetes Service external IP:
|
||||
|
||||
```bash
|
||||
kubectl get svc azurite -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
|
||||
```
|
||||
|
||||
4. Add `/etc/hosts` entries on your workstation and point all Azurite account FQDNs to that Service IP (not `127.0.0.1`):
|
||||
|
||||
```
|
||||
<service_ip> <accountname>.blob.core.windows.net <accountname>.queue.core.windows.net <accountname>.table.core.windows.net
|
||||
```
|
||||
|
||||
### Using Node.js
|
||||
|
||||
To install the Azure Storage Emulator natively on your machine, ensure you have Node.js (with npm) and Caddy HTTP Server installed, and follow these steps:
|
||||
|
||||
1. Clone the repository:
|
||||
|
||||
@@ -59,9 +94,7 @@ To install the Azure Storage Emulator natively on your machine, ensure you have
|
||||
rm -rf azurite
|
||||
```
|
||||
|
||||
6. Install the Caddy HTTP server.
|
||||
|
||||
7. Create an `accounts.env` file in the same directory as the `run-server.sh` script with the following content:
|
||||
6. Create an `accounts.env` file in the same directory as the `run-server.sh` script with the following content:
|
||||
|
||||
```bash
|
||||
AZURITE_ACCOUNTS=accountname:accountkey
|
||||
@@ -79,13 +112,13 @@ To install the Azure Storage Emulator natively on your machine, ensure you have
|
||||
echo -n "your-seed-string" | base64
|
||||
```
|
||||
|
||||
8. Add the following line to your `/etc/hosts` file to map the custom domain names to localhost:
|
||||
7. Add the following line to your `/etc/hosts` file to map the custom domain names to localhost:
|
||||
|
||||
```
|
||||
127.0.0.1 <accountname>.blob.core.windows.net <accountname>.queue.core.windows.net <accountname>.table.core.windows.net
|
||||
```
|
||||
|
||||
9. Run the server:
|
||||
8. Run the server:
|
||||
|
||||
```bash
|
||||
./run-server.sh
|
||||
@@ -97,6 +130,72 @@ To install the Azure Storage Emulator natively on your machine, ensure you have
|
||||
./run-server.sh --oauth
|
||||
```
|
||||
|
||||
## Accessing the blob storage
|
||||
|
||||
### RClone
|
||||
|
||||
RClone is a command-line program to manage files on cloud storage. You can use it to interact with the Azure Storage Emulator the same way you would with the real Azure Storage service. Edit the rclone.conf file and add the following configuration:
|
||||
|
||||
```ini
|
||||
[azurite]
|
||||
type = azureblob
|
||||
account = accountname
|
||||
key = accountkey
|
||||
```
|
||||
|
||||
or, if you want to use simulated OAuth authentication:
|
||||
|
||||
```ini
|
||||
[azurite]
|
||||
type = azureblob
|
||||
account = accountname
|
||||
env_auth = true
|
||||
```
|
||||
|
||||
Now, you can use rclone commands to interact with the emulator. For example, to list the containers in the blob service:
|
||||
|
||||
```bash
|
||||
rclone ls azurite:
|
||||
```
|
||||
|
||||
> **Note**: On modern Linux distributions and MacOS systems the `rclone.conf` file is typically located at `~/.config/rclone/rclone.conf`.
|
||||
|
||||
### Terraform
|
||||
|
||||
Use the following Terraform Azure RM backend configuration to use the Azure Storage Emulator as the backend for storing Terraform state:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
backend "azurerm" {
|
||||
storage_account_name = "accountname"
|
||||
container_name = "tfstate"
|
||||
key = "terraform.tfstate"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
and initialize the module:
|
||||
|
||||
```bash
|
||||
terraform init -backend-config=access_key=__base64_encoded_account_key__
|
||||
```
|
||||
|
||||
> **Note**: Be aware that AI Agents may generate or suggest using the `endpoint` parameter, which will not work. You have to create *fake* account FQDNs in your `/etc/hosts` file as described in the installation steps.
|
||||
|
||||
|
||||
You can use OAuth simulation with Terraform by adding the `use_azuread_auth` parameter to the backend configuration:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
backend "azurerm" {
|
||||
storage_account_name = "accountname"
|
||||
container_name = "tfstate"
|
||||
key = "terraform.tfstate"
|
||||
use_azuread_auth = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Command Reference
|
||||
|
||||
### `run-server.sh`
|
||||
@@ -137,10 +236,20 @@ Accepted flags:
|
||||
- `--latest`: Uses the latest released version of Azurite from GitHub as the base for the container image. This flag cannot be used together with `--version`.
|
||||
- `--registry`: Specifies the container registry to which the built image will be pushed. If not provided, the image will only be built locally and not tagged with registry prefix.
|
||||
|
||||
### `run.sh`
|
||||
### `start-azurite`
|
||||
|
||||
The script runs the Azure Storage Emulator using a supported container runtime (Docker or Apple `container` command). It accepts the same flag as `run-server.sh` to enable OAuth simulation (`--oauth` or `-o`). It also assumes `AZURITE_DIR` is either set in the environment or empty (not set), in which case it will default to the `./storage` subdirectory of the current directory. The script mounts the specified storage directory into the container, allowing you to persist data and access the generated SSL certificates on the host machine.
|
||||
|
||||
The default image name is `azurite:latest`, but it can be overridden by setting the `AZURITE_IMAGE` environment variable before running the script. For example:
|
||||
|
||||
```bash
|
||||
AZURITE_IMAGE=myregistry/azurite:latest ./start-azurite
|
||||
```
|
||||
|
||||
Both `AZURITE_DIR` and `AZURITE_IMAGE` should be set in the shell profile if you are running the emulator as a local Azure Storage replacement for development purposes.
|
||||
|
||||
> **Remember**: Make backups of the storage directory when the container is not running.
|
||||
|
||||
You have to use the same procedure as for `run-server.sh` to install the generated CA certificate as a trusted root certificate in your system to avoid SSL errors when connecting to the emulator.
|
||||
|
||||
## Reference
|
||||
@@ -148,3 +257,4 @@ You have to use the same procedure as for `run-server.sh` to install the generat
|
||||
- [Azure Storage Emulator GitHub Repository](https://github.com/azure/azurite)
|
||||
- [Azure Storage Emulator Documentation](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite)
|
||||
- [Caddy Server](https://caddyserver.com)
|
||||
- [RClone](https://rclone.org)
|
||||
|
||||
69
azurite-deployment.yaml
Normal file
69
azurite-deployment.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: azurite-storage
|
||||
labels:
|
||||
app.kubernetes.io/name: azurite
|
||||
app.kubernetes.io/component: storage-emulator
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Mi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: azurite
|
||||
labels:
|
||||
app.kubernetes.io/name: azurite
|
||||
app.kubernetes.io/component: storage-emulator
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: azurite
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: azurite
|
||||
app.kubernetes.io/component: storage-emulator
|
||||
spec:
|
||||
containers:
|
||||
- name: azurite
|
||||
image: azurite:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- --oauth
|
||||
ports:
|
||||
- name: https
|
||||
containerPort: 443
|
||||
protocol: TCP
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: azurite-accounts
|
||||
volumeMounts:
|
||||
- name: storage
|
||||
mountPath: /storage
|
||||
volumes:
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: azurite-storage
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: azurite
|
||||
labels:
|
||||
app.kubernetes.io/name: azurite
|
||||
app.kubernetes.io/component: storage-emulator
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
selector:
|
||||
app.kubernetes.io/name: azurite
|
||||
ports:
|
||||
- name: https
|
||||
port: 443
|
||||
targetPort: 443
|
||||
protocol: TCP
|
||||
2
build.sh
2
build.sh
@@ -48,7 +48,7 @@ else
|
||||
fi
|
||||
|
||||
echo "Effective command line arguments:" ${ARCH[@]} ${VERSION_ARG[@]} ${TAG_ARGS[@]}
|
||||
if command -v dockerd &> /dev/null; then
|
||||
if command -v docker &> /dev/null; then
|
||||
docker build "${ARCH[@]}" "${VERSION_ARG[@]}" "${TAG_ARGS[@]}" .
|
||||
elif command -v container &> /dev/null; then
|
||||
container build "${ARCH[@]}" "${VERSION_ARG[@]}" "${TAG_ARGS[@]}" .
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
function make_ca() {
|
||||
# Use the provided directory argument or default to AZURITE_DIR if not provided
|
||||
local CERT_DIR="${1:-$AZURITE_DIR}"
|
||||
local CERT_DIR="$1"
|
||||
local CA_NAME="$2"
|
||||
|
||||
if [[ ! -d "$CERT_DIR" ]]; then
|
||||
if [[ -z "$CERT_DIR" || -z "$CA_NAME" || ! -d "$CERT_DIR" ]]; then
|
||||
echo "ERROR: Certificate directory $CERT_DIR does not exist."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Generate CA certificate and key if they don't exist
|
||||
if [[ ! -f "$CERT_DIR/ca_cert.pem" || ! -f "$CERT_DIR/ca_key.pem" ]]; then
|
||||
echo "Generating CA certificate and key..."
|
||||
echo "Generating CA certificate '$CA_NAME' and key..."
|
||||
if ! openssl req \
|
||||
-x509 \
|
||||
-newkey rsa:4096 \
|
||||
@@ -17,36 +18,97 @@ function make_ca() {
|
||||
-out "$CERT_DIR/ca_cert.pem" \
|
||||
-days 3650 \
|
||||
-nodes \
|
||||
-subj "/CN=Azurite CA" \
|
||||
-subj "/CN=${CA_NAME}" \
|
||||
-text \
|
||||
-addext "basicConstraints=critical,CA:TRUE,pathlen:0"; then
|
||||
echo "Error: Failed to generate CA certificate and key." >&2
|
||||
echo "ERROR: Failed to generate CA certificate and key." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function _is_ip() {
|
||||
if [[ "$1" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function _is_dns() {
|
||||
if [[ "$1" =~ ^[a-z0-9-]+(\.[a-z0-9-]+)*$ ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function make_server_cert() {
|
||||
local ACCOUNT_NAME="${1:-devstoreaccount1}"
|
||||
local CERT_DIR="${2:-$AZURITE_DIR}"
|
||||
local CERT_DIR="$1"
|
||||
local CERT_SUBJECT_NAME="$2"
|
||||
shift 2
|
||||
|
||||
if [[ ! -d "$CERT_DIR" ]]; then
|
||||
if [[ -z "$CERT_DIR" || ! -d "$CERT_DIR" ]]; then
|
||||
echo "ERROR: Certificate directory $CERT_DIR does not exist."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "$CERT_SUBJECT_NAME" ]]; then
|
||||
echo "ERROR: Subject name is required." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _is_dns "$CERT_SUBJECT_NAME"; then
|
||||
echo "ERROR: Invalid subject name '$CERT_SUBJECT_NAME'. Must be a valid DNS name." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CERT_DIR/ca_cert.pem" || ! -f "$CERT_DIR/ca_key.pem" ]]; then
|
||||
echo "ERROR: CA certificate and key not found in $CERT_DIR. Please call make_ca first." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Calculate the "account" name from the subject name, the hostname part before the first dot
|
||||
local CERT_NAME="${CERT_SUBJECT_NAME%%.*}"
|
||||
|
||||
# Start with the subjectAltName extension containing the main DNS name
|
||||
local SANS=("DNS:${CERT_SUBJECT_NAME}")
|
||||
|
||||
# Combine the remaining arguments into a single string for the subjectAltName extension
|
||||
while [[ $# -gt 0 ]]; do
|
||||
if _is_ip "$1"; then
|
||||
SANS+=("IP:$1")
|
||||
elif _is_dns "$1"; then
|
||||
SANS+=("DNS:$1")
|
||||
else
|
||||
echo "ERROR: Invalid SAN entry '$1'" >&2
|
||||
return 1
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
# Join the SAN entries with commas for the OpenSSL command
|
||||
local SANS_EXT="subjectAltName=$(IFS=,; echo "${SANS[*]}")"
|
||||
|
||||
echo "Generating server certificate for '$CERT_SUBJECT_NAME' with SANs:"
|
||||
for san in "${SANS[@]}"; do
|
||||
echo " - $san"
|
||||
done
|
||||
|
||||
# Generate server certificate and key if they don't exist
|
||||
if [[ ! -f "$CERT_DIR/${ACCOUNT_NAME}_cert.pem" || ! -f "$CERT_DIR/${ACCOUNT_NAME}_key.pem" ]]; then
|
||||
if [[ ! -f "$CERT_DIR/${CERT_NAME}_cert.pem" || ! -f "$CERT_DIR/${CERT_NAME}_key.pem" ]]; then
|
||||
echo "Generating server certificate and key..."
|
||||
if ! openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-keyout "$CERT_DIR/${ACCOUNT_NAME}_key.pem" \
|
||||
-keyout "$CERT_DIR/${CERT_NAME}_key.pem" \
|
||||
-nodes \
|
||||
-subj "/CN=${ACCOUNT_NAME}.blob.core.windows.net" \
|
||||
-subj "/CN=${CERT_SUBJECT_NAME}" \
|
||||
-addext "basicConstraints=critical,CA:FALSE" \
|
||||
-addext "keyUsage=digitalSignature,keyEncipherment" \
|
||||
-addext "extendedKeyUsage=serverAuth,clientAuth" \
|
||||
-addext "subjectAltName=DNS:${ACCOUNT_NAME}.blob.core.windows.net,DNS:${ACCOUNT_NAME}.queue.core.windows.net,DNS:${ACCOUNT_NAME}.table.core.windows.net,DNS:${ACCOUNT_NAME}.blob.localhost,DNS:${ACCOUNT_NAME}.queue.localhost,DNS:${ACCOUNT_NAME}.table.localhost,DNS:localhost,IP:127.0.0.1" \
|
||||
-addext "$SANS_EXT" \
|
||||
| openssl x509 \
|
||||
-req \
|
||||
-CA "$CERT_DIR/ca_cert.pem" \
|
||||
@@ -55,9 +117,60 @@ function make_server_cert() {
|
||||
-copy_extensions copyall \
|
||||
-days 365 \
|
||||
-text \
|
||||
-out "$CERT_DIR/${ACCOUNT_NAME}_cert.pem"; then
|
||||
echo "Error: Failed to generate server certificate and key." >&2
|
||||
exit 1
|
||||
-out "$CERT_DIR/${CERT_NAME}_cert.pem"; then
|
||||
echo "ERROR: Failed to generate server certificate and key." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function make_pfx() {
|
||||
local CERT_DIR="$1"
|
||||
local CERT_NAME="$2"
|
||||
local PFX_PASSWORD="${3:-}"
|
||||
|
||||
if [[ -z "$CERT_DIR" || ! -d "$CERT_DIR" ]]; then
|
||||
echo "ERROR: Certificate directory $CERT_DIR does not exist."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "$CERT_NAME" ]]; then
|
||||
echo "ERROR: Certificate name is required." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CERT_DIR/${CERT_NAME}_cert.pem" || ! -f "$CERT_DIR/${CERT_NAME}_key.pem" ]]; then
|
||||
echo "ERROR: Server certificate and key not found in $CERT_DIR. Please call make_server_cert first." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CERT_DIR/ca_cert.pem" || ! -f "$CERT_DIR/ca_key.pem" ]]; then
|
||||
echo "ERROR: CA certificate and key not found in $CERT_DIR. Please call make_ca first." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PFX_PASSWORD" ]]; then
|
||||
PFX_PASSWORD="changeit"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CERT_DIR/${CERT_NAME}.pfx" ]]; then
|
||||
echo -n "Generating PKCS#12 (PFX) file..."
|
||||
if ! openssl pkcs12 \
|
||||
-export -out "$CERT_DIR/${CERT_NAME}.pfx" \
|
||||
-inkey "$CERT_DIR/${CERT_NAME}_key.pem" \
|
||||
-in "$CERT_DIR/${CERT_NAME}_cert.pem" \
|
||||
-certfile "$CERT_DIR/ca_cert.pem" \
|
||||
-password pass:"$PFX_PASSWORD"; then
|
||||
echo "ERROR: Failed to generate PKCS#12 (PFX) file." >&2
|
||||
return 1
|
||||
fi
|
||||
echo "done."
|
||||
else
|
||||
echo "PKCS#12 (PFX) file already exists, aborting generation."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
13
compose.yaml
Normal file
13
compose.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
services:
|
||||
azurite:
|
||||
image: azurite:latest
|
||||
container_name: azurite
|
||||
command:
|
||||
- --oauth
|
||||
ports:
|
||||
- "443:443"
|
||||
env_file:
|
||||
- $HOME/.azurite/accounts.env
|
||||
volumes:
|
||||
- $HOME/.azurite/storage:/storage
|
||||
restart: unless-stopped
|
||||
@@ -5,14 +5,37 @@ set -e
|
||||
# Include certificate generation functions.
|
||||
. /app/cert-functions.sh
|
||||
|
||||
function make_account_cert() {
|
||||
local CERT_DIR="$1"
|
||||
local ACCOUNT_NAME="${2:-devstoreaccount1}"
|
||||
# -addext "subjectAltName=DNS:${ACCOUNT_NAME}.blob.core.windows.net,DNS:${ACCOUNT_NAME}.queue.core.windows.net,DNS:${ACCOUNT_NAME}.table.core.windows.net,DNS:${ACCOUNT_NAME}.blob.localhost,DNS:${ACCOUNT_NAME}.queue.localhost,DNS:${ACCOUNT_NAME}.table.localhost,DNS:localhost,IP:127.0.0.1"
|
||||
|
||||
make_server_cert "$CERT_DIR" "${ACCOUNT_NAME}.blob.core.windows.net" \
|
||||
"${ACCOUNT_NAME}.queue.core.windows.net" \
|
||||
"${ACCOUNT_NAME}.table.core.windows.net" \
|
||||
"${ACCOUNT_NAME}.blob.localhost" \
|
||||
"${ACCOUNT_NAME}.queue.localhost" \
|
||||
"${ACCOUNT_NAME}.table.localhost" \
|
||||
"localhost" \
|
||||
"127.0.0.1"
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
# Setup default storage location, account name and accounts file path.
|
||||
AZURITE_DIR="/storage"
|
||||
AZURITE_STORAGE="${AZURITE_STORAGE:-/storage}"
|
||||
|
||||
# Check, if the AZURITE_ACCOUNTS variable is set
|
||||
if [[ -z "$AZURITE_ACCOUNTS" ]]; then
|
||||
if [[ -f "$AZURITE_STORAGE/accounts.env" ]]; then
|
||||
set -a
|
||||
source "$AZURITE_STORAGE/accounts.env"
|
||||
set +a
|
||||
else
|
||||
# Generate a default account
|
||||
export AZURITE_ACCOUNTS="devstoreaccount1:$(openssl rand -base64 32)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Look up the account name from the AZURITE_ACCOUNTS variable, which is in the format "accountName:accountKey1:accountKey2;accountName2:accountKey1:accountKey2"
|
||||
ACCOUNT_NAME=$(echo "$AZURITE_ACCOUNTS" | cut -f 1 -d ';' | cut -f 1 -d ':')
|
||||
@@ -29,6 +52,7 @@ cat <<EOF >> /etc/hosts
|
||||
EOF
|
||||
|
||||
OAUTH_ARGS=()
|
||||
NO_CADDY=
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -37,6 +61,10 @@ while [[ $# -gt 0 ]]; do
|
||||
# Ensure Caddy is disabled when using OAuth, as Azurite does not support OAuth behind a reverse proxy.
|
||||
shift
|
||||
;;
|
||||
--no-caddy)
|
||||
NO_CADDY=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1"
|
||||
exit 1
|
||||
@@ -45,27 +73,31 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
# Ensure certificates are generated before starting Azurite or Caddy.
|
||||
if ! make_ca "$AZURITE_DIR"; then
|
||||
if ! make_ca "$AZURITE_STORAGE" "Azurite CA $(date +%Y.%m)"; then
|
||||
echo "Error: Failed to create CA certificate and key." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! make_server_cert "$ACCOUNT_NAME" "$AZURITE_DIR"; then
|
||||
if ! make_account_cert "$AZURITE_STORAGE" "$ACCOUNT_NAME"; then
|
||||
echo "Error: Failed to create server certificate and key." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$NO_CADDY" ]]; then
|
||||
# Generate a Caddyfile configuration based on the account name and storage directory.
|
||||
sed -E "s/__ACCOUNT_NAME__/${ACCOUNT_NAME}/g; s|__AZURITE_DIR__|${AZURITE_DIR}|g" /app/Caddyfile.example > "$AZURITE_DIR/Caddyfile"
|
||||
|
||||
caddy start --config "$AZURITE_DIR/Caddyfile" # Use start not run, start does not block the shell process.
|
||||
|
||||
sed -E "s/__ACCOUNT_NAME__/${ACCOUNT_NAME}/g; s|__AZURITE_STORAGE__|${AZURITE_STORAGE}|g" /app/Caddyfile.example > "$AZURITE_STORAGE/Caddyfile"
|
||||
# Start Caddy in the background to handle HTTPS requests and route them to Azurite.
|
||||
caddy start --config "$AZURITE_STORAGE/Caddyfile" # Use start not run, start does not block the shell process.
|
||||
HOST_ARGS=("--blobHost" "127.0.0.1" "--queueHost" "127.0.0.1" "--tableHost" "127.0.0.1")
|
||||
else
|
||||
HOST_ARGS=("--blobHost" "0.0.0.0" "--queueHost" "0.0.0.0" "--tableHost" "0.0.0.0")
|
||||
fi
|
||||
|
||||
PORT_ARGS=("--blobPort" "10000" "--queuePort" "10001" "--tablePort" "10002")
|
||||
|
||||
# Start Azurite with the appropriate arguments based on the configuration.
|
||||
exec node /app/azurite/src/azurite.js \
|
||||
--disableTelemetry \
|
||||
--location "$AZURITE_DIR" \
|
||||
--key "$AZURITE_DIR/${ACCOUNT_NAME}_key.pem" --cert "$AZURITE_DIR/${ACCOUNT_NAME}_cert.pem" \
|
||||
--location "$AZURITE_STORAGE" \
|
||||
--key "$AZURITE_STORAGE/${ACCOUNT_NAME}_key.pem" --cert "$AZURITE_STORAGE/${ACCOUNT_NAME}_cert.pem" \
|
||||
"${HOST_ARGS[@]}" "${PORT_ARGS[@]}" "${OAUTH_ARGS[@]}"
|
||||
|
||||
27
run.sh
27
run.sh
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
AZURITE_DIR="${AZURITE_DIR:-./storage}"
|
||||
CONTAINER_ARGS=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-o|--oauth)
|
||||
# OAuth support
|
||||
CONTAINER_ARGS+=("--oauth")
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if command -v dockerd &> /dev/null; then
|
||||
docker run --rm -d --name azurite --env-file accounts.env -p 443:443 -v "$AZURITE_DIR":/storage azurite:latest "${CONTAINER_ARGS[@]}"
|
||||
elif command -v container &> /dev/null; then
|
||||
container run --rm -d --name azurite --env-file accounts.env -p 443:443 --mount type=bind,source="$AZURITE_DIR",target=/storage azurite:latest "${CONTAINER_ARGS[@]}"
|
||||
else
|
||||
echo "Neither supported container runtime found." >&2
|
||||
exit 1
|
||||
fi
|
||||
37
start-azurite
Executable file
37
start-azurite
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
AZURITE_DIR="${AZURITE_DIR:-$(pwd)}"
|
||||
CONTAINER_ARGS=()
|
||||
AZURITE_IMAGE="${AZURITE_IMAGE:-azurite:latest}"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-o|--oauth)
|
||||
# OAuth support
|
||||
CONTAINER_ARGS+=("--oauth")
|
||||
shift
|
||||
;;
|
||||
-d|--azurite-dir)
|
||||
if [[ -n "$2" && -d "$2" ]]; then
|
||||
AZURITE_DIR="$2"
|
||||
shift 2
|
||||
else
|
||||
echo "Error: Selected directory does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if command -v dockerd &> /dev/null; then
|
||||
docker run --rm -d --name azurite --env-file "$AZURITE_DIR/accounts.env" -p 443:443 -v "$AZURITE_DIR/storage":/storage "$AZURITE_IMAGE" "${CONTAINER_ARGS[@]}"
|
||||
elif command -v container &> /dev/null; then
|
||||
container run -c 2 -m 512M --rm -d --name azurite --env-file "$AZURITE_DIR/accounts.env" -p 443:443 --mount type=bind,source="$AZURITE_DIR/storage",target=/storage "$AZURITE_IMAGE" "${CONTAINER_ARGS[@]}"
|
||||
else
|
||||
echo "Neither supported container runtime found." >&2
|
||||
exit 1
|
||||
fi
|
||||
17
test/init.sh
17
test/init.sh
@@ -1,15 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
AZURITE_DIR="$HOME/.azurite"
|
||||
if [[ ! -d "$AZURITE_DIR" ]]; then
|
||||
echo "Error: Azurite data directory not found at $AZURITE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$AZURITE_DIR/accounts.env" ]]; then
|
||||
echo "Error: accounts.env file not found at $AZURITE_DIR/accounts.env" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ACCESS_KEY=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--key|-k)
|
||||
if [[ ! -f "../accounts.env" ]]; then
|
||||
echo "Error: accounts.env file not found at ../accounts.env" >&2
|
||||
if [[ ! -f "$AZURITE_DIR/accounts.env" ]]; then
|
||||
echo "Error: accounts.env file not found at $AZURITE_DIR/accounts.env" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Load the accounts.env file to get the ACCESS_KEY variable.
|
||||
source "../accounts.env"
|
||||
source "$AZURITE_DIR/accounts.env"
|
||||
ACCESS_KEY=$(echo "$AZURITE_ACCOUNTS" | cut -f 1 -d ';' | cut -f 2 -d ':')
|
||||
;;
|
||||
*)
|
||||
|
||||
Reference in New Issue
Block a user