Compare commits

..

18 Commits

Author SHA1 Message Date
abbb0842fc Fixed incorrect AI autocomplete. 2026-03-22 10:17:22 +01:00
eac8adbcfa fix: include CA name in certificate generation for improved clarity 2026-03-21 19:01:35 +01:00
d7ad25c4d6 fix: add resource limits to container run command for azurite 2026-03-21 19:01:07 +01:00
241f70cb22 feat: add VSCode settings for shell script association with start-azurite 2026-03-21 19:01:00 +01:00
6822c65a7a fix: update subject in server certificate generation to use the full subject name 2026-03-03 13:23:33 +01:00
fb7ec2ac9e fix: improve feedback during PFX file generation and secure password handling 2026-03-03 12:40:17 +01:00
76c812794c fix: correct parameter name from '-passout' to '-password' in make_pfx function 2026-03-03 12:24:57 +01:00
3b9c295a35 feat: enhance certificate generation functions and add make_account_cert for streamlined server cert creation 2026-03-03 11:54:47 +01:00
3a068149a7 fix: update init.sh to use correct path for accounts.env file 2026-03-02 11:52:38 +01:00
ea7905d7c7 feat: add Kubernetes manifest for Azurite deployment 2026-03-02 07:34:00 +01:00
d5a715fcfc update: revise installation instructions in README and adjust Azurite image in docker-compose 2026-03-02 07:08:55 +01:00
815278e918 feat: add docker-compose configuration for Azurite service 2026-03-02 06:45:36 +01:00
58c31e73bf fix: update Caddyfile.example to use __AZURITE_STORAGE__ for certificate and key paths 2026-02-28 20:39:52 +01:00
1a66e46615 update: rename run.sh to start-azurite and enhance documentation for environment variables 2026-02-28 20:13:35 +01:00
93fb89446d fix: use variable for AZURITE_IMAGE in docker run commands 2026-02-28 19:52:02 +01:00
c8ac9ddebf update: rename run.sh to start-azurite. 2026-02-28 19:46:51 +01:00
ffdfc2697b fix: update run.sh to use current directory for AZURITE_DIR and correct env-file paths 2026-02-28 19:45:10 +01:00
b698521720 fix: update entrypoint.sh to source accounts from accounts.env and improve Caddy handling 2026-02-28 19:45:00 +01:00
11 changed files with 438 additions and 75 deletions

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"files.associations": {
"start-azurite": "shellscript"
}
}

View File

@@ -2,31 +2,31 @@
# It uses /etc/hosts entries to route requests to the emulator # It uses /etc/hosts entries to route requests to the emulator
# Replace "__ACCOUNT_NAME__" with a desired storage account name if needed # Replace "__ACCOUNT_NAME__" with a desired storage account name if needed
__ACCOUNT_NAME__.blob.core.windows.net { __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 { reverse_proxy https://__ACCOUNT_NAME__.blob.core.windows.net:10000 {
transport http { transport http {
tls 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 { __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 { reverse_proxy https://__ACCOUNT_NAME__.queue.core.windows.net:10001 {
transport http { transport http {
tls 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 { __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 { reverse_proxy https://__ACCOUNT_NAME__.table.core.windows.net:10002 {
transport http { transport http {
tls tls
tls_trust_pool file __AZURITE_DIR__/ca_cert.pem tls_trust_pool file __AZURITE_STORAGE__/ca_cert.pem
} }
} }
} }

132
README.md
View File

@@ -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. 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. 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: 3. Run the emulator container:
```bash ```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: 1. Clone the repository:
@@ -59,9 +94,7 @@ To install the Azure Storage Emulator natively on your machine, ensure you have
rm -rf azurite rm -rf azurite
``` ```
6. Install the Caddy HTTP server. 6. Create an `accounts.env` file in the same directory as the `run-server.sh` script with the following content:
7. Create an `accounts.env` file in the same directory as the `run-server.sh` script with the following content:
```bash ```bash
AZURITE_ACCOUNTS=accountname:accountkey 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 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 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 ```bash
./run-server.sh ./run-server.sh
@@ -97,6 +130,72 @@ To install the Azure Storage Emulator natively on your machine, ensure you have
./run-server.sh --oauth ./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 ## Command Reference
### `run-server.sh` ### `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`. - `--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. - `--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 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. 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 ## 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 GitHub Repository](https://github.com/azure/azurite)
- [Azure Storage Emulator Documentation](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite) - [Azure Storage Emulator Documentation](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite)
- [Caddy Server](https://caddyserver.com) - [Caddy Server](https://caddyserver.com)
- [RClone](https://rclone.org)

69
azurite-deployment.yaml Normal file
View 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

View File

@@ -48,7 +48,7 @@ else
fi fi
echo "Effective command line arguments:" ${ARCH[@]} ${VERSION_ARG[@]} ${TAG_ARGS[@]} 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[@]}" . docker build "${ARCH[@]}" "${VERSION_ARG[@]}" "${TAG_ARGS[@]}" .
elif command -v container &> /dev/null; then elif command -v container &> /dev/null; then
container build "${ARCH[@]}" "${VERSION_ARG[@]}" "${TAG_ARGS[@]}" . container build "${ARCH[@]}" "${VERSION_ARG[@]}" "${TAG_ARGS[@]}" .

View File

@@ -1,15 +1,16 @@
function make_ca() { function make_ca() {
# Use the provided directory argument or default to AZURITE_DIR if not provided # 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." echo "ERROR: Certificate directory $CERT_DIR does not exist."
return 1 return 1
fi fi
# Generate CA certificate and key if they don't exist # Generate CA certificate and key if they don't exist
if [[ ! -f "$CERT_DIR/ca_cert.pem" || ! -f "$CERT_DIR/ca_key.pem" ]]; then 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 \ if ! openssl req \
-x509 \ -x509 \
-newkey rsa:4096 \ -newkey rsa:4096 \
@@ -17,36 +18,97 @@ function make_ca() {
-out "$CERT_DIR/ca_cert.pem" \ -out "$CERT_DIR/ca_cert.pem" \
-days 3650 \ -days 3650 \
-nodes \ -nodes \
-subj "/CN=Azurite CA" \ -subj "/CN=${CA_NAME}" \
-text \ -text \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0"; then -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 return 1
fi fi
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() { function make_server_cert() {
local ACCOUNT_NAME="${1:-devstoreaccount1}" local CERT_DIR="$1"
local CERT_DIR="${2:-$AZURITE_DIR}" 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." echo "ERROR: Certificate directory $CERT_DIR does not exist."
return 1 return 1
fi 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 # 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..." echo "Generating server certificate and key..."
if ! openssl req \ if ! openssl req \
-newkey rsa:4096 \ -newkey rsa:4096 \
-keyout "$CERT_DIR/${ACCOUNT_NAME}_key.pem" \ -keyout "$CERT_DIR/${CERT_NAME}_key.pem" \
-nodes \ -nodes \
-subj "/CN=${ACCOUNT_NAME}.blob.core.windows.net" \ -subj "/CN=${CERT_SUBJECT_NAME}" \
-addext "basicConstraints=critical,CA:FALSE" \ -addext "basicConstraints=critical,CA:FALSE" \
-addext "keyUsage=digitalSignature,keyEncipherment" \ -addext "keyUsage=digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage=serverAuth,clientAuth" \ -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 \ | openssl x509 \
-req \ -req \
-CA "$CERT_DIR/ca_cert.pem" \ -CA "$CERT_DIR/ca_cert.pem" \
@@ -55,9 +117,60 @@ function make_server_cert() {
-copy_extensions copyall \ -copy_extensions copyall \
-days 365 \ -days 365 \
-text \ -text \
-out "$CERT_DIR/${ACCOUNT_NAME}_cert.pem"; then -out "$CERT_DIR/${CERT_NAME}_cert.pem"; then
echo "Error: Failed to generate server certificate and key." >&2 echo "ERROR: Failed to generate server certificate and key." >&2
exit 1 return 1
fi fi
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
View 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

View File

@@ -5,13 +5,36 @@ set -e
# Include certificate generation functions. # Include certificate generation functions.
. /app/cert-functions.sh . /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. # 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 # Check, if the AZURITE_ACCOUNTS variable is set
if [[ -z "$AZURITE_ACCOUNTS" ]]; then if [[ -z "$AZURITE_ACCOUNTS" ]]; then
# Generate a default account if [[ -f "$AZURITE_STORAGE/accounts.env" ]]; then
export AZURITE_ACCOUNTS="devstoreaccount1:$(openssl rand -base64 32)" set -a
source "$AZURITE_STORAGE/accounts.env"
set +a
else
# Generate a default account
export AZURITE_ACCOUNTS="devstoreaccount1:$(openssl rand -base64 32)"
fi
fi fi
# Look up the account name from the AZURITE_ACCOUNTS variable, which is in the format "accountName:accountKey1:accountKey2;accountName2:accountKey1:accountKey2" # Look up the account name from the AZURITE_ACCOUNTS variable, which is in the format "accountName:accountKey1:accountKey2;accountName2:accountKey1:accountKey2"
@@ -29,6 +52,7 @@ cat <<EOF >> /etc/hosts
EOF EOF
OAUTH_ARGS=() OAUTH_ARGS=()
NO_CADDY=
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in 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. # Ensure Caddy is disabled when using OAuth, as Azurite does not support OAuth behind a reverse proxy.
shift shift
;; ;;
--no-caddy)
NO_CADDY=true
shift
;;
*) *)
echo "Unknown argument: $1" echo "Unknown argument: $1"
exit 1 exit 1
@@ -45,27 +73,31 @@ while [[ $# -gt 0 ]]; do
done done
# Ensure certificates are generated before starting Azurite or Caddy. # 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 echo "Error: Failed to create CA certificate and key." >&2
exit 1 exit 1
fi 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 echo "Error: Failed to create server certificate and key." >&2
exit 1 exit 1
fi fi
# Generate a Caddyfile configuration based on the account name and storage directory. if [[ -z "$NO_CADDY" ]]; then
sed -E "s/__ACCOUNT_NAME__/${ACCOUNT_NAME}/g; s|__AZURITE_DIR__|${AZURITE_DIR}|g" /app/Caddyfile.example > "$AZURITE_DIR/Caddyfile" # Generate a Caddyfile configuration based on the account name and storage directory.
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
caddy start --config "$AZURITE_DIR/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")
PORT_ARGS=("--blobPort" "10000" "--queuePort" "10001" "--tablePort" "10002") PORT_ARGS=("--blobPort" "10000" "--queuePort" "10001" "--tablePort" "10002")
# Start Azurite with the appropriate arguments based on the configuration. # Start Azurite with the appropriate arguments based on the configuration.
exec node /app/azurite/src/azurite.js \ exec node /app/azurite/src/azurite.js \
--disableTelemetry \ --disableTelemetry \
--location "$AZURITE_DIR" \ --location "$AZURITE_STORAGE" \
--key "$AZURITE_DIR/${ACCOUNT_NAME}_key.pem" --cert "$AZURITE_DIR/${ACCOUNT_NAME}_cert.pem" \ --key "$AZURITE_STORAGE/${ACCOUNT_NAME}_key.pem" --cert "$AZURITE_STORAGE/${ACCOUNT_NAME}_cert.pem" \
"${HOST_ARGS[@]}" "${PORT_ARGS[@]}" "${OAUTH_ARGS[@]}" "${HOST_ARGS[@]}" "${PORT_ARGS[@]}" "${OAUTH_ARGS[@]}"

27
run.sh
View File

@@ -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
View 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

View File

@@ -1,15 +1,26 @@
#!/usr/bin/env bash #!/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="" ACCESS_KEY=""
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--key|-k) --key|-k)
if [[ ! -f "../accounts.env" ]]; then if [[ ! -f "$AZURITE_DIR/accounts.env" ]]; then
echo "Error: accounts.env file not found at ../accounts.env" >&2 echo "Error: accounts.env file not found at $AZURITE_DIR/accounts.env" >&2
exit 1 exit 1
fi fi
# Load the accounts.env file to get the ACCESS_KEY variable. # 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 ':') ACCESS_KEY=$(echo "$AZURITE_ACCOUNTS" | cut -f 1 -d ';' | cut -f 2 -d ':')
;; ;;
*) *)