Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,145 +109,145 @@
path: build/

deploy:
runs-on: gh-runner-large
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
needs: [build, determine-environment]
environment: ${{ needs.determine-environment.outputs.environment }}
steps:
- name: Download build artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: build-output
path: build/

- name: Install azcopy
run: |
wget -O azcopy.tar.gz https://aka.ms/downloadazcopy-v10-linux
tar -xf azcopy.tar.gz --strip-components=1
sudo mv azcopy /usr/local/bin/
azcopy --version

- name: Install Azure CLI
run: |
if ! command -v az &> /dev/null; then
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
fi
az version

- name: Upload to Azure Blob Storage with AzCopy
run: |
echo "Deploying to ${{ needs.determine-environment.outputs.environment }} environment"
echo "Starting sync of changed files..."

# Create SAS token for azcopy (using account key)
end_date=$(date -u -d "2 hours" '+%Y-%m-%dT%H:%MZ')
sas_token=$(az storage container generate-sas \
--account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} \
--account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} \
--name '$web' \
--permissions dlrw \
--expiry $end_date \
--output tsv)

azcopy sync "./build/" \
"https://${{ secrets.STORAGE_ACCOUNT_NAME }}.blob.core.windows.net/\$web?$sas_token" \
--delete-destination=true \
--log-level=INFO \
--cap-mbps=0 \
--block-size-mb=4

echo "Sync completed!"

- name: Set MIME types for all file types
run: |
echo "Setting MIME types for all file types..."

# Web files
echo "Setting MIME types for web files..."
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.css" --content-type "text/css" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.js" --content-type "application/javascript" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.mjs" --content-type "application/javascript" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.json" --content-type "application/json" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.html" --content-type "text/html" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.htm" --content-type "text/html" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.xml" --content-type "application/xml" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.txt" --content-type "text/plain" --no-progress || true

# Images
echo "Setting MIME types for images..."
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.png" --content-type "image/png" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.jpg" --content-type "image/jpeg" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.jpeg" --content-type "image/jpeg" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.gif" --content-type "image/gif" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.webp" --content-type "image/webp" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.svg" --content-type "image/svg+xml" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.ico" --content-type "image/x-icon" --no-progress || true

# Fonts
echo "Setting MIME types for fonts..."
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.woff" --content-type "font/woff" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.woff2" --content-type "font/woff2" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.ttf" --content-type "font/ttf" --no-progress || true
az storage blob update-batch --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} --source '$web' --pattern "*.otf" --content-type "font/otf" --no-progress || true

echo "All MIME types set successfully!"

- name: Set public URL metadata on blobs
env:
APP_EXTERNAL_URL: ${{ secrets.APP_EXTERNAL_URL || vars.APP_EXTERNAL_URL }}
run: |
if [[ -z "$APP_EXTERNAL_URL" ]]; then
echo "APP_EXTERNAL_URL not configured, skipping public URL metadata"
exit 0
fi
PUBLIC_URL="${APP_EXTERNAL_URL%/}"

echo "Setting public_url metadata on blobs (base: $PUBLIC_URL)..."

ACCOUNT="${{ secrets.STORAGE_ACCOUNT_NAME }}"
KEY="${{ secrets.STORAGE_ACCOUNT_KEY }}"

blob_count=0
az storage blob list \
--account-name "$ACCOUNT" \
--account-key "$KEY" \
--container-name '$web' \
--query "[].name" -o tsv | \
while IFS= read -r blob; do
az storage blob metadata update \
--account-name "$ACCOUNT" \
--account-key "$KEY" \
--container-name '$web' \
--name "$blob" \
--metadata "public_url=${PUBLIC_URL}/${blob}" \
--output none &

blob_count=$((blob_count + 1))
# Run up to 20 concurrent updates, then wait for the batch
if (( blob_count % 20 == 0 )); then
wait
echo " Processed $blob_count blobs..."
fi
done
wait

echo "Public URL metadata set on all blobs"

- name: Purge CDN endpoint (if configured)
run: |
if [[ -n "${{ secrets.CDN_ENDPOINT_NAME }}" ]] && [[ -n "${{ secrets.CDN_PROFILE_NAME }}" ]] && [[ -n "${{ secrets.CDN_RESOURCE_GROUP }}" ]]; then
echo "Note: CDN purge requires Azure login. Skipping CDN purge when using storage key authentication."
echo "To use CDN purge, you'll need to use Azure AD authentication or purge CDN manually."
else
echo "CDN configuration not found, skipping CDN purge."
fi

- name: Display deployment URL
run: |
echo "Deployment complete!"
echo "Environment: ${{ needs.determine-environment.outputs.environment }}"
echo "URL: https://${{ secrets.STORAGE_ACCOUNT_NAME }}.z13.web.core.windows.net"
if [[ -n "${{ secrets.CUSTOM_DOMAIN }}" ]]; then
echo "Custom Domain: ${{ secrets.CUSTOM_DOMAIN }}"
fi
echo "All files deployed with proper MIME types for optimal browser compatibility!"

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
26 changes: 14 additions & 12 deletions docs/identityrecovery/3.1/admin/configuration/entraid.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The table displays the following information:
- Duration – The time the collection took to complete
- Status – Collection state as idle, waiting, error, or success
- Details – Information about any errors that occurred during the last backup
- Actions – Displays the icons used to collect, edit, and delete the respective tenant configuration
- Actions – Displays the icons for collecting, editing, and deleting the respective tenant configuration

- Run backup – Click the **Play** icon to start a new collection (backup) on the respective
tenant if you need a collection outside the configured schedule
Expand Down Expand Up @@ -51,16 +51,18 @@ dropdown. The following options are available:
environments at Impact Level 5.
- China (21Vianet) – Microsoft Azure operated by 21Vianet for organizations in China.

![Add Tenant Configuration wizard - Cloud Environment dropdown](/images/identityrecovery/3.1/product/configuration/entra_id/entra_id_configuration_page1a.png)

:::note
The cloud environment determines the authentication and Microsoft Graph endpoints used for all
backup, rollback, and recovery operations for this tenant. Select the environment that matches where
your Entra tenant is hosted before entering credentials.
The cloud environment determines which authentication and Microsoft Graph endpoints Identity
Recovery uses for this tenant's backup, rollback, and recovery operations. Select the environment
where your Entra tenant resides before you enter credentials.
:::

**Step 3 –** Enter a tenant [example.tenant.com] in the Tenant field.

**Step 4 –** Enter the Client Id [CLIENTID] for backups, rollbacks, and
recoveries in the Client ID field.
**Step 4 –** In the Client ID field, enter the Client Id [CLIENTID] for backups, rollbacks, and
recoveries.

**Step 5 –** Enter the secret for the application registration in the Secret field.

Expand Down Expand Up @@ -124,15 +126,15 @@ If you don't want notifications, skip this step.

![Add Tenant Configuration wizard - Confirm page](/images/identityrecovery/3.1/product/configuration/entra_id/entra_id_configuration_page4.png)

**Step 12 –** The Confirm page displays a summary of the settings you provided on the pages of the
wizard. Use the Back button to return to a previous page and change any setting. Click **Done**
to finish the wizard.
**Step 12 –** The Confirm page displays a summary of the settings you provided in the wizard. Use
the Back button to return to a previous page and change any setting. Click **Done** to finish the
wizard.

The new tenant appears on the Entra Id page.

Backups begin as scheduled. On the first scheduled instance, Identity Recovery performs a complete
backup of the tenant. Then, subsequent backups only include the incremental changes that occurred
since the previous backup.
backup of the tenant. Subsequent backups only include the incremental changes that occurred since
the previous backup.

### Edit Tenant Configuration

Expand All @@ -141,6 +143,6 @@ Tenant Configuration wizard opens.

**Step 2 –** Modify the settings you want to change for the tenant configuration.

**Step 3 –** The Confirm page displays a summary of the settings you provided on the pages of the wizard. Use the Back button to return to a previous page and change any setting. Click **Done** to finish the wizard.
**Step 3 –** The Confirm page displays a summary of the settings you provided in the wizard. Use the Back button to return to a previous page and change any setting. Click **Done** to finish the wizard.

Identity Recovery updates the tenant configuration and backups resume as scheduled.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.