Compare commits
43 Commits
c8ac9ddebf
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 3755329fe6 | |||
| 6a1f332372 | |||
| 8d967d7ad7 | |||
| f825835744 | |||
| ea6277ba3b | |||
| 8800154d37 | |||
| 8c454fa2fc | |||
| 149f8a30eb | |||
| 2631d4ff85 | |||
| b342be88f3 | |||
| 795e1c6740 | |||
| a19036f10d | |||
| 4c66ee38ba | |||
| 7f1027c6e0 | |||
| 9d1546a1bc | |||
| 00459cbb1c | |||
| 2af06a3bbf | |||
| b092c00e27 | |||
| 32bbc40979 | |||
| 58d0a96bfe | |||
| 12b14460e9 | |||
| c3c078fa7f | |||
| 47efc09d18 | |||
| 5a840f6577 | |||
| 8fdbce7fb4 | |||
| 4f1d78f174 | |||
| b17d34ae2b | |||
| d5cddbdd8c | |||
| abbb0842fc | |||
| eac8adbcfa | |||
| d7ad25c4d6 | |||
| 241f70cb22 | |||
| 6822c65a7a | |||
| fb7ec2ac9e | |||
| 76c812794c | |||
| 3b9c295a35 | |||
| 3a068149a7 | |||
| ea7905d7c7 | |||
| d5a715fcfc | |||
| 815278e918 | |||
| 58c31e73bf | |||
| 1a66e46615 | |||
| 93fb89446d |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ storage
|
||||
**/.terraform.lock.hcl
|
||||
Caddyfile
|
||||
*.env
|
||||
storage
|
||||
|
||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"start-azurite": "shellscript"
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
# Caddyfile for Azure Storage Emulator
|
||||
# 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
|
||||
reverse_proxy https://__ACCOUNT_NAME__.blob.core.windows.net:10000 {
|
||||
transport http {
|
||||
tls
|
||||
tls_trust_pool file __AZURITE_DIR__/ca_cert.pem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__ACCOUNT_NAME__.queue.core.windows.net {
|
||||
tls __AZURITE_DIR__/__ACCOUNT_NAME___cert.pem __AZURITE_DIR__/__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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__ACCOUNT_NAME__.table.core.windows.net {
|
||||
tls __AZURITE_DIR__/__ACCOUNT_NAME___cert.pem __AZURITE_DIR__/__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
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Caddyfile.template
Normal file
30
Caddyfile.template
Normal file
@@ -0,0 +1,30 @@
|
||||
# Caddyfile for Azure Storage Emulator
|
||||
__ACCOUNT_NAME__.blob.core.windows.net {
|
||||
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_STORAGE__/ca_cert.pem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__ACCOUNT_NAME__.queue.core.windows.net {
|
||||
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_STORAGE__/ca_cert.pem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__ACCOUNT_NAME__.table.core.windows.net {
|
||||
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_STORAGE__/ca_cert.pem
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,8 @@ RUN npm pkg set scripts.prepare="echo no-prepare"
|
||||
RUN npm ci --omit=dev --unsafe-perm
|
||||
|
||||
WORKDIR /app
|
||||
COPY ./cert-functions.sh ./
|
||||
COPY ./entrypoint.sh .
|
||||
COPY ./Caddyfile.example .
|
||||
COPY ./Caddyfile.template .
|
||||
RUN chmod +x entrypoint.sh
|
||||
|
||||
ENTRYPOINT [ "/app/entrypoint.sh" ]
|
||||
|
||||
179
README.md
179
README.md
@@ -4,27 +4,49 @@ 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 and Caddy HTTP Server.
|
||||
|
||||
### 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.
|
||||
|
||||
2. Build the emulator image using the provided Dockerfile:
|
||||
2. Create a custom non-public certificate for the emulator. Use the provided `make-cert.sh` script to generate a self-signed CA certificate and a server certificate for the specified storage account name. The script will use `CA_DIR` (default: `./storage`), `CA_NAME` (default: `Azurite Emulator CA`), and `STORAGE_ACCOUNT_NAME` (default: `azuritelocal`) environment variables to determine the storage location for the certificates, the name of the CA, and the storage account name for which the server certificate will be generated. For example:
|
||||
|
||||
```bash
|
||||
./make-cert.sh
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
CA_DIR=./myca CA_NAME="My Custom CA" STORAGE_ACCOUNT_NAME=myaccount ./make-cert.sh
|
||||
```
|
||||
|
||||
You can run the script multiple times with different `STORAGE_ACCOUNT_NAME` values to generate certificates for multiple storage accounts if needed. Just make sure to use the same `CA_DIR` and `CA_NAME` for all of them (or use the defaults) to ensure they are signed by the same CA.
|
||||
|
||||
3. Build the emulator image using the provided Dockerfile:
|
||||
|
||||
```bash
|
||||
./build.sh
|
||||
```
|
||||
|
||||
3. Run the emulator container:
|
||||
or pull it from the Docker Hub registry using image name: `skoszewski/azurite:latest`.
|
||||
|
||||
4. 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 Node.js and Caddy HTTP Server
|
||||
|
||||
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 +81,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,52 +99,87 @@ 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
|
||||
```
|
||||
|
||||
8. Create a certificate for the specified account name using the `make-cert.sh` as described in the container runtime installation steps.
|
||||
|
||||
9. Run the server:
|
||||
|
||||
```bash
|
||||
./run-server.sh
|
||||
```
|
||||
|
||||
You can add the `--oauth` or `-o` flag to simulate OAuth authentication.
|
||||
## Accessing the blob storage
|
||||
|
||||
```bash
|
||||
./run-server.sh --oauth
|
||||
```
|
||||
### RClone
|
||||
|
||||
## Command Reference
|
||||
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:
|
||||
|
||||
### `run-server.sh`
|
||||
|
||||
The script is the entry point for starting the Azure Storage Emulator natively. It discovers the account name and key from the `accounts.env` file, generates the necessary SSL certificates, configures Caddy for HTTPS endpoints, and starts the Azurite server with the appropriate settings.
|
||||
|
||||
It accepts the following optional flag: `--oauth` or `-o`. It enables OAuth simulation for the emulator. When this flag is set, the emulator simulates OAuth authentication flows, allowing you to test scenarios that involve Entra ID authentication. It does not implement a real authentication flow; instead, it accepts any valid token.
|
||||
|
||||
The script assumes that both Azurite and Caddy are installed and available in the system's PATH. It also assumes that the `accounts.env` file is properly configured with at least one account name and key, and that the `/etc/hosts` file contains the necessary entries for the custom domain names, e.g. `accountname.blob.core.windows.net`, `accountname.queue.core.windows.net`, and `accountname.table.core.windows.net`.
|
||||
|
||||
The storage location is determined by the `AZURITE_DIR` environment variable, which defaults to the relative `storage` subdirectory of the current directory if not set. Ensure that the specified directory is writable by the user running the script, as Azurite will need to create and manage files for the emulated storage accounts.
|
||||
|
||||
The script will generate self-signed SSL certificates for the specified account name and store them in the storage directory. Caddy will be configured to use these certificates for the HTTPS endpoints. The emulator will be accessible at the following endpoints:
|
||||
|
||||
- Blob service: `https://accountname.blob.core.windows.net`
|
||||
- Queue service: `https://accountname.queue.core.windows.net`
|
||||
- Table service: `https://accountname.table.core.windows.net`
|
||||
|
||||
You need to add `storage/ca_cert.pem` as a trusted root certificate in your system to avoid SSL errors when connecting to the emulator.
|
||||
|
||||
For Linux-based systems, you can use the following commands to add the certificate to the trusted store:
|
||||
|
||||
```bash
|
||||
sudo cp storage/ca_cert.pem /usr/local/share/ca-certificates/azurite_ca_cert.crt
|
||||
sudo update-ca-certificates
|
||||
```ini
|
||||
[azurite]
|
||||
type = azureblob
|
||||
account = accountname
|
||||
key = accountkey
|
||||
```
|
||||
|
||||
For macOS, you can use the Keychain Access application to import the certificate and mark it as trusted. Windows users can use the Certificate Manager to import the certificate into the "Trusted Root Certification Authorities" store.
|
||||
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
|
||||
|
||||
### `build.sh`
|
||||
|
||||
@@ -137,14 +192,52 @@ 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`
|
||||
Used environment variables:
|
||||
|
||||
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.
|
||||
- `AZURITE_IMAGE`: Overrides the default image name (`azurite:latest`) for the built container image. This can be useful if you want to use a different naming convention or push to a specific registry. The `--registry` flag will replace the registry part of the image name, but it will not override the entire name, so you can still use a custom image name with the registry prefix if needed.
|
||||
|
||||
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.
|
||||
### `start-azurite`
|
||||
|
||||
The script runs the Azure Storage Emulator using a supported container runtime (Docker or Apple `container` command). It enables OAuth and starts Caddy by defualt.
|
||||
|
||||
> **Remember**: Make backups of the storage directory when the container is not running.
|
||||
|
||||
Accepted flags:
|
||||
|
||||
- `--no-oauth` - disables OAuth simulation in the emulator. When this flag is set, you have to use the account key for authentication.
|
||||
- `--no-caddy` - disables Caddy server and runs Azurite with its built-in HTTP server. This will result in the emulator being accessible over three HTTPS endpoints (ports: 10000, 10001, 10002). Use this flag if you want to run the emulator and proxy the endpoints yourself. Note that you have to configure your proxy to accept the certificate supplied for the emulator. Caddy uses `tls_trust_pool file <pem_cert_path>` directive.
|
||||
|
||||
Used environment variables:
|
||||
|
||||
- `AZURITE_DIR`: Specifies the directory on the host machine where the emulator will store its data. This directory will be mounted as `/storage` in the container, allowing the emulator to persist data across container restarts.
|
||||
- `AZURITE_IMAGE`: Specifies the name of the container image to use when running the emulator. If not set, it defaults to `azurite:latest`, which is the default tag used by the `build.sh` script.
|
||||
|
||||
### `run-server.sh`
|
||||
|
||||
The script is the entry point for starting the Azure Storage Emulator natively. It discovers the account name and key from the `accounts.env` file, checks for the necessary SSL certificates, configures Caddy for HTTPS endpoints, and starts the Azurite server with the appropriate settings.
|
||||
|
||||
The script assumes that both Azurite and Caddy are installed and available in the system's PATH. It also assumes that the `accounts.env` file is properly configured with at least one account name and key, and that the `/etc/hosts` file contains the necessary entries mapped to `127.0.0.1` for the custom domain names, e.g. `accountname.blob.core.windows.net`, `accountname.queue.core.windows.net`, and `accountname.table.core.windows.net`.
|
||||
|
||||
The storage location is determined by the `AZURITE_DIR` environment variable. Data files are stored in the `storage` subdirectory. The directory structure pointed to by `AZURITE_DIR` will be created if it does not exist.
|
||||
|
||||
The script will use the certificate for the listed endpoints. Caddy will be configured to use that certificate for all HTTPS endpoints, therefore the certificate must have all the required SANs (Subject Alternative Names) for the endpoints and must be trusted by the system. The emulator will be accessible at the following endpoints:
|
||||
|
||||
- Blob service: `https://accountname.blob.core.windows.net`
|
||||
- Queue service: `https://accountname.queue.core.windows.net`
|
||||
- Table service: `https://accountname.table.core.windows.net`
|
||||
|
||||
For Debian-based systems, you can use the following commands to add the certificate to the trusted store:
|
||||
|
||||
```bash
|
||||
sudo cp storage/ca_cert.pem /usr/local/share/ca-certificates/azurite_ca_cert.crt
|
||||
sudo update-ca-certificates
|
||||
```
|
||||
|
||||
For macOS, you can use the Keychain Access application to import the certificate and mark it as trusted. Windows users can use the Certificate Manager to import the certificate into the "Trusted Root Certification Authorities" store.
|
||||
|
||||
## Reference
|
||||
|
||||
- [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)
|
||||
|
||||
16
build.sh
16
build.sh
@@ -4,6 +4,7 @@ ARCH=()
|
||||
VERSION_ARG=()
|
||||
VERSION=""
|
||||
REGISTRY=""
|
||||
AZURITE_IMAGE="${AZURITE_IMAGE:-azurite:latest}"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -33,22 +34,21 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$REGISTRY" ]]; then
|
||||
IMAGE="azurite"
|
||||
else
|
||||
IMAGE="$REGISTRY/azurite"
|
||||
if [[ ! -z "$REGISTRY" ]]; then
|
||||
# Prepend the registry to the image name for tagging.
|
||||
AZURITE_IMAGE="$REGISTRY/${AZURITE_IMAGE#*/}"
|
||||
fi
|
||||
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
TAG_ARGS=("--tag" "$IMAGE:latest")
|
||||
TAG_ARGS=("--tag" "${AZURITE_IMAGE%:*}:latest")
|
||||
elif [[ "$VERSION" == "latest" ]]; then
|
||||
TAG_ARGS=("--tag" "$IMAGE:${LATEST_TAG#v}" "--tag" "$IMAGE:latest")
|
||||
TAG_ARGS=("--tag" "${AZURITE_IMAGE%:*}:${LATEST_TAG#v}" "--tag" "${AZURITE_IMAGE%:*}:latest")
|
||||
else
|
||||
TAG_ARGS=("--tag" "$IMAGE:${VERSION#v}")
|
||||
TAG_ARGS=("--tag" "${AZURITE_IMAGE%:*}:${VERSION#v}")
|
||||
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,63 +0,0 @@
|
||||
function make_ca() {
|
||||
# Use the provided directory argument or default to AZURITE_DIR if not provided
|
||||
local CERT_DIR="${1:-$AZURITE_DIR}"
|
||||
|
||||
if [[ ! -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..."
|
||||
if ! openssl req \
|
||||
-x509 \
|
||||
-newkey rsa:4096 \
|
||||
-keyout "$CERT_DIR/ca_key.pem" \
|
||||
-out "$CERT_DIR/ca_cert.pem" \
|
||||
-days 3650 \
|
||||
-nodes \
|
||||
-subj "/CN=Azurite CA" \
|
||||
-text \
|
||||
-addext "basicConstraints=critical,CA:TRUE,pathlen:0"; then
|
||||
echo "Error: Failed to generate CA certificate and key." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function make_server_cert() {
|
||||
local ACCOUNT_NAME="${1:-devstoreaccount1}"
|
||||
local CERT_DIR="${2:-$AZURITE_DIR}"
|
||||
|
||||
if [[ ! -d "$CERT_DIR" ]]; then
|
||||
echo "ERROR: Certificate directory $CERT_DIR does not exist."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 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
|
||||
echo "Generating server certificate and key..."
|
||||
if ! openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-keyout "$CERT_DIR/${ACCOUNT_NAME}_key.pem" \
|
||||
-nodes \
|
||||
-subj "/CN=${ACCOUNT_NAME}.blob.core.windows.net" \
|
||||
-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" \
|
||||
| openssl x509 \
|
||||
-req \
|
||||
-CA "$CERT_DIR/ca_cert.pem" \
|
||||
-CAkey "$CERT_DIR/ca_key.pem" \
|
||||
-set_serial "0x$(openssl rand -hex 16)" \
|
||||
-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
|
||||
fi
|
||||
fi
|
||||
}
|
||||
11
compose.yaml
Normal file
11
compose.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
azurite:
|
||||
image: azurite:latest
|
||||
container_name: azurite
|
||||
ports:
|
||||
- "443:443"
|
||||
env_file:
|
||||
- $HOME/.azurite/accounts.env
|
||||
volumes:
|
||||
- $HOME/.azurite/storage:/storage
|
||||
restart: unless-stopped
|
||||
@@ -1,47 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Include certificate generation functions.
|
||||
. /app/cert-functions.sh
|
||||
|
||||
# Setup default storage location, account name and accounts file path.
|
||||
AZURITE_STORAGE="${AZURITE_STORAGE:-/storage}"
|
||||
set -euo pipefail
|
||||
|
||||
# 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
|
||||
echo "[ERROR] AZURITE_ACCOUNTS variable is not set." >&2
|
||||
exit 1
|
||||
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 ':')
|
||||
|
||||
# Ensure /etc/hosts contains an entry the Azure endpoint names,
|
||||
# so Caddy can route requests to the correct service based on the hostname.
|
||||
if grep -q "${ACCOUNT_NAME}" /etc/hosts; then
|
||||
cp -a /etc/hosts /etc/hosts.bak && sed -E "/${ACCOUNT_NAME}/d" /etc/hosts > /etc/hosts
|
||||
# Check, if the certificate for the account exists.
|
||||
if [[ ! -f "/storage/${ACCOUNT_NAME}_cert.pem" ]] || [[ ! -f "/storage/${ACCOUNT_NAME}_key.pem" ]]; then
|
||||
echo "[ERROR] Certificate or key for account ${ACCOUNT_NAME} not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<EOF >> /etc/hosts
|
||||
|
||||
127.0.0.1 ${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
|
||||
EOF
|
||||
|
||||
OAUTH_ARGS=()
|
||||
NO_CADDY=
|
||||
OAUTH_ARGS=("--oauth" "basic")
|
||||
NO_CADDY=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--oauth)
|
||||
OAUTH_ARGS=("--oauth" "basic")
|
||||
# Ensure Caddy is disabled when using OAuth, as Azurite does not support OAuth behind a reverse proxy.
|
||||
--no-oauth)
|
||||
OAUTH_ARGS=()
|
||||
shift
|
||||
;;
|
||||
--no-caddy)
|
||||
@@ -55,31 +37,28 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
# Ensure certificates are generated before starting Azurite or Caddy.
|
||||
if ! make_ca "$AZURITE_STORAGE"; then
|
||||
echo "Error: Failed to create CA certificate and key." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "$NO_CADDY" ]]; then
|
||||
HOST_ARGS=("--blobHost" "0.0.0.0" "--queueHost" "0.0.0.0" "--tableHost" "0.0.0.0")
|
||||
else
|
||||
# Create /etc/hosts entries for the emulator endpoints, so that they can be accessed via their standard Azure Storage hostnames.
|
||||
ALTNAMES=()
|
||||
for name in blob queue table; do
|
||||
ALTNAMES+=("${ACCOUNT_NAME}.${name}.core.windows.net")
|
||||
done
|
||||
echo "127.0.0.1 ${ALTNAMES[@]}" >> /etc/hosts
|
||||
|
||||
if ! make_server_cert "$ACCOUNT_NAME" "$AZURITE_STORAGE"; then
|
||||
echo "Error: Failed to create server certificate and key." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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"
|
||||
|
||||
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_STORAGE__|/storage|g" /app/Caddyfile.template > "/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.
|
||||
caddy start --config "/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")
|
||||
fi
|
||||
|
||||
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")
|
||||
|
||||
# Start Azurite with the appropriate arguments based on the configuration.
|
||||
exec node /app/azurite/src/azurite.js \
|
||||
--disableTelemetry \
|
||||
--location "$AZURITE_STORAGE" \
|
||||
--key "$AZURITE_STORAGE/${ACCOUNT_NAME}_key.pem" --cert "$AZURITE_STORAGE/${ACCOUNT_NAME}_cert.pem" \
|
||||
--location "/storage" \
|
||||
--key "/storage/${ACCOUNT_NAME}_key.pem" --cert "/storage/${ACCOUNT_NAME}_cert.pem" \
|
||||
"${HOST_ARGS[@]}" "${PORT_ARGS[@]}" "${OAUTH_ARGS[@]}"
|
||||
|
||||
49
make-cert.sh
Executable file
49
make-cert.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# This script creates a self-signed CA and a server certificate for the Azurite Emulator.
|
||||
#
|
||||
# For more sophisticated certificate management, consider using Simple CA project
|
||||
# from: https://gitea.koszewscy.waw.pl/slawek/simple-ca.git
|
||||
|
||||
CA_DIR="${CA_DIR:-./storage}"
|
||||
CA_NAME="${CA_NAME:-Azurite Emulator CA}"
|
||||
STORAGE_ACCOUNT_NAME="${STORAGE_ACCOUNT_NAME:-azuritelocal}"
|
||||
mkdir -p "$CA_DIR"
|
||||
if [[ ! -f "${CA_DIR}/ca_cert.pem" || ! -f "${CA_DIR}/ca_key.pem" ]]; then
|
||||
openssl req \
|
||||
-x509 -noenc -text \
|
||||
-newkey rsa:4096 \
|
||||
-keyout "${CA_DIR}/ca_key.pem" \
|
||||
-out "${CA_DIR}/ca_cert.pem" \
|
||||
-days 3650 \
|
||||
-subj "/CN=$CA_NAME" \
|
||||
-addext "basicConstraints=critical,CA:TRUE,pathlen:0"
|
||||
HASH=$(openssl x509 -in "${CA_DIR}/ca_cert.pem" -noout -hash 2>/dev/null)
|
||||
ln -sf ca_cert.pem "${CA_DIR}/$HASH.0"
|
||||
fi
|
||||
ALTNAMES=()
|
||||
for endpoint in blob queue table; do
|
||||
ALTNAMES+=("DNS:${STORAGE_ACCOUNT_NAME}.${endpoint}.core.windows.net")
|
||||
done
|
||||
openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-noenc \
|
||||
-keyout "${CA_DIR}/${STORAGE_ACCOUNT_NAME}_key.pem" \
|
||||
-subj "/CN=${STORAGE_ACCOUNT_NAME}.blob.core.windows.net" \
|
||||
-addext "basicConstraints=critical,CA:FALSE" \
|
||||
-addext "keyUsage=digitalSignature, keyEncipherment" \
|
||||
-addext "extendedKeyUsage=serverAuth" \
|
||||
-addext "subjectAltName=$(IFS=, ; echo "${ALTNAMES[*]}")" \
|
||||
| openssl x509 \
|
||||
-req -text \
|
||||
-CA "${CA_DIR}/ca_cert.pem" \
|
||||
-CAkey "${CA_DIR}/ca_key.pem" \
|
||||
-copy_extensions copyall \
|
||||
-days 365 \
|
||||
-out "${CA_DIR}/${STORAGE_ACCOUNT_NAME}_cert.pem"
|
||||
openssl verify -CApath "${CA_DIR}" "${CA_DIR}/${STORAGE_ACCOUNT_NAME}_cert.pem"
|
||||
cat <<EOF
|
||||
Add the following line to your /etc/hosts file to resolve the emulator endpoints:
|
||||
|
||||
127.0.0.1 $(IFS=' '; echo "${ALTNAMES[@]#DNS:}")
|
||||
EOF
|
||||
@@ -1,34 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# Include certificate generation functions.
|
||||
. "$SCRIPT_DIR/cert-functions.sh"
|
||||
AZURITE_DIR="${AZURITE_DIR:-$SCRIPT_DIR}"
|
||||
|
||||
AZURITE_DIR="$SCRIPT_DIR/storage"
|
||||
|
||||
if [[ ! -d "$AZURITE_DIR" ]]; then
|
||||
echo "No accounts found"
|
||||
exit 0
|
||||
if ! mkdir -p "$AZURITE_DIR/storage"; then
|
||||
echo "ERROR: Failed to create storage directory at $AZURITE_DIR/storage. Please ensure the path is correct and writable."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$AZURITE_ACCOUNTS" && -f "$SCRIPT_DIR/accounts.env" ]]; then
|
||||
if [[ -z "$AZURITE_ACCOUNTS" && -f "$AZURITE_DIR/accounts.env" ]]; then
|
||||
set -a
|
||||
. "$SCRIPT_DIR/accounts.env"
|
||||
source "$AZURITE_DIR/accounts.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
if [[ -z "$AZURITE_ACCOUNTS" ]]; then
|
||||
echo "[ERROR] AZURITE_ACCOUNTS variable is not set." >&2
|
||||
exit 1
|
||||
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 ':')
|
||||
|
||||
# Ensure /etc/hosts contains an entry the Azure endpoint names,
|
||||
# so Caddy can route requests to the correct service based on the hostname.
|
||||
if ! grep -qE "${ACCOUNT_NAME}\.blob\.core\.windows\.net" /etc/hosts ||
|
||||
! grep -qE "${ACCOUNT_NAME}\.queue\.core\.windows\.net" /etc/hosts ||
|
||||
! grep -qE "${ACCOUNT_NAME}\.table\.core\.windows\.net" /etc/hosts; then
|
||||
echo "ERROR: /etc/hosts does not contain entries for the Azure endpoints. Please ensure the following line is present in /etc/hosts:"
|
||||
echo -e "\n127.0.0.1\t${ACCOUNT_NAME}.blob.core.windows.net ${ACCOUNT_NAME}.queue.core.windows.net ${ACCOUNT_NAME}.table.core.windows.net"
|
||||
exit 1
|
||||
fi
|
||||
ALTNAMES=()
|
||||
for name in blob queue table; do
|
||||
if ! grep -qE "${ACCOUNT_NAME}.${name}.core.windows.net" /etc/hosts; then
|
||||
echo "ERROR: /etc/hosts does not contain an entry for ${ACCOUNT_NAME}.${name}.core.windows.net mapping to 127.0.0.1."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if ! command -v azurite &> /dev/null; then
|
||||
echo "ERROR: Azurite is not installed. Please install it with 'npm install -g azurite'"
|
||||
@@ -40,13 +42,12 @@ if ! command -v caddy &> /dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OAUTH_ARGS=()
|
||||
OAUTH_ARGS=("--oauth" "basic")
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--oauth|-o)
|
||||
OAUTH_ARGS=("--oauth" "basic")
|
||||
# Ensure Caddy is disabled when using OAuth, as Azurite does not support OAuth behind a reverse proxy.
|
||||
--no-oauth)
|
||||
OAUTH_ARGS=()
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
@@ -56,21 +57,16 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
# Ensure certificates are generated before starting Azurite or Caddy.
|
||||
if ! make_ca "$AZURITE_DIR"; then
|
||||
echo "Error: Failed to create CA certificate and key." >&2
|
||||
if [[ ! -f "$AZURITE_DIR/storage/ca_cert.pem" ||
|
||||
! -f "$AZURITE_DIR/storage/ca_key.pem" ||
|
||||
! -f "$AZURITE_DIR/storage/${ACCOUNT_NAME}_cert.pem" ||
|
||||
! -f "$AZURITE_DIR/storage/${ACCOUNT_NAME}_key.pem" ]]; then
|
||||
echo "ERROR: SSL certificate or key files not found in $AZURITE_DIR/storage. Please run 'make-cert.sh' to create the necessary certificates and keys."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! make_server_cert "$ACCOUNT_NAME" "$AZURITE_DIR"; then
|
||||
echo "Error: Failed to create server certificate and key." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CERT_ARGS=()
|
||||
|
||||
# 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" "$SCRIPT_DIR/Caddyfile.example" > "$AZURITE_DIR/Caddyfile"
|
||||
sed -E "s|__ACCOUNT_NAME__|${ACCOUNT_NAME}|g; s|__AZURITE_STORAGE__|${AZURITE_DIR}/storage|g" "$SCRIPT_DIR/Caddyfile.template" > "$AZURITE_DIR/Caddyfile"
|
||||
|
||||
echo "Starting Caddy server..."
|
||||
caddy start --config "$AZURITE_DIR/Caddyfile" # Use start not run, start does not block the shell process.
|
||||
@@ -80,7 +76,7 @@ trap "echo 'Stopping Caddy server...'; caddy stop" EXIT INT TERM HUP KILL STOP
|
||||
echo "Starting Azurite..."
|
||||
azurite \
|
||||
--disableTelemetry \
|
||||
--location "$AZURITE_DIR" \
|
||||
--location "$AZURITE_DIR/storage" \
|
||||
--blobHost 127.0.0.1 --queueHost 127.0.0.1 --tableHost 127.0.0.1 \
|
||||
--key "$AZURITE_DIR/${ACCOUNT_NAME}_key.pem" --cert "$AZURITE_DIR/${ACCOUNT_NAME}_cert.pem" \
|
||||
--key "$AZURITE_DIR/storage/${ACCOUNT_NAME}_key.pem" --cert "$AZURITE_DIR/storage/${ACCOUNT_NAME}_cert.pem" \
|
||||
"${OAUTH_ARGS[@]}"
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
AZURITE_DIR="${AZURITE_DIR:-$(pwd)}"
|
||||
set -euo pipefail
|
||||
|
||||
AZURITE_DIR="${AZURITE_DIR:-}"
|
||||
CONTAINER_ARGS=()
|
||||
AZURITE_IMAGE="${AZURITE_IMAGE:-azurite:latest}"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-o|--oauth)
|
||||
# OAuth support
|
||||
CONTAINER_ARGS+=("--oauth")
|
||||
--no-oauth|--no-caddy)
|
||||
# Pass these flags to the container, so that it can configure Azurite accordingly.
|
||||
CONTAINER_ARGS+=("$1")
|
||||
shift
|
||||
;;
|
||||
-d|--azurite-dir)
|
||||
@@ -20,16 +23,58 @@ while [[ $# -gt 0 ]]; do
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
echo "Error: 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:latest "${CONTAINER_ARGS[@]}"
|
||||
# Check, if the AZURITE_DIR variable is set and is a valid directory
|
||||
if [[ -z "$AZURITE_DIR" || ! -d "$AZURITE_DIR" ]]; then
|
||||
echo "Error: AZURITE_DIR is not set or is not a valid directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check, if the accounts.env file exists in the AZURITE_DIR directory
|
||||
if [[ ! -f "$AZURITE_DIR/accounts.env" ]]; then
|
||||
echo "Error: accounts.env file not found in AZURITE_DIR directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$AZURITE_DIR/accounts.env"
|
||||
if [[ -z "$AZURITE_ACCOUNTS" ]]; then
|
||||
echo "Error: AZURITE_ACCOUNTS variable is not set in accounts.env file." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ACCOUNT_NAME=$(echo "$AZURITE_ACCOUNTS" | cut -f 1 -d ';' | cut -f 1 -d ':')
|
||||
|
||||
# Check, if the certificate for the account exists.
|
||||
if [[ ! -f "$AZURITE_DIR/storage/${ACCOUNT_NAME}_cert.pem" ]] || [[ ! -f "$AZURITE_DIR/storage/${ACCOUNT_NAME}_key.pem" ]]; then
|
||||
echo "Error: Certificate or key for account ${ACCOUNT_NAME} not found in AZURITE_DIR directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if command -v docker &> /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 --rm -d --name azurite --env-file "$AZURITE_DIR/accounts.env" -p 443:443 --mount type=bind,source="$AZURITE_DIR/storage",target=/storage azurite:latest "${CONTAINER_ARGS[@]}"
|
||||
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
|
||||
|
||||
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