mirror of
https://github.com/bitwarden/server.git
synced 2024-11-22 12:15:36 +01:00
Bitwarden Unified Self-Host project (#2410)
This commit is contained in:
parent
3481fd76c1
commit
194dfe7e14
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@ -0,0 +1,3 @@
|
||||
**/bin
|
||||
**/obj
|
||||
**/node_modules
|
173
.github/workflows/build-self-host.yml
vendored
173
.github/workflows/build-self-host.yml
vendored
@ -2,12 +2,181 @@
|
||||
name: Build Self-Host
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- "l10n_master"
|
||||
- "gh-pages"
|
||||
paths-ignore:
|
||||
- ".github/workflows/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stub:
|
||||
name: Stub
|
||||
build-docker:
|
||||
name: Build Docker image
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
|
||||
########## Set up Docker ##########
|
||||
- name: Set up QEMU emulators
|
||||
uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325
|
||||
|
||||
########## Build Docker Image ##########
|
||||
- name: Login to Azure - QA Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }}
|
||||
|
||||
- name: Login to Azure ACR
|
||||
run: az acr login -n bitwardenqa
|
||||
|
||||
- name: Generate Docker image tag
|
||||
id: tag
|
||||
run: |
|
||||
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name
|
||||
if [[ "$IMAGE_TAG" == "master" ]]; then
|
||||
IMAGE_TAG=dev
|
||||
fi
|
||||
|
||||
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build Docker image
|
||||
uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5
|
||||
with:
|
||||
context: .
|
||||
file: docker-unified/Dockerfile
|
||||
platforms: |
|
||||
linux/amd64,
|
||||
linux/arm/v7,
|
||||
linux/arm64/v8
|
||||
push: true
|
||||
tags: bitwardenqa.azurecr.io/self-host:${{ steps.tag.outputs.image_tag }}
|
||||
|
||||
- name: Log out of Docker
|
||||
run: docker logout
|
||||
|
||||
########## DockerHub ##########
|
||||
- name: Login to Azure - Prod Subscription
|
||||
if: |
|
||||
false
|
||||
&& (github.ref == 'refs/heads/master' ||
|
||||
github.ref == 'refs/heads/rc' ||
|
||||
github.ref == 'refs/heads/hotfix-rc')
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
if: |
|
||||
false
|
||||
&& (github.ref == 'refs/heads/master' ||
|
||||
github.ref == 'refs/heads/rc' ||
|
||||
github.ref == 'refs/heads/hotfix-rc')
|
||||
id: retrieve-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af
|
||||
with:
|
||||
keyvault: "bitwarden-prod-kv"
|
||||
secrets: "docker-password,
|
||||
docker-username,
|
||||
dct-delegate-2-repo-passphrase,
|
||||
dct-delegate-2-key"
|
||||
|
||||
- name: Log into Docker
|
||||
if: |
|
||||
false
|
||||
&& (github.ref == 'refs/heads/master' ||
|
||||
github.ref == 'refs/heads/rc' ||
|
||||
github.ref == 'refs/heads/hotfix-rc')
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ steps.retrieve-secrets.outputs.docker-username }}
|
||||
DOCKER_PASSWORD: ${{ steps.retrieve-secrets.outputs.docker-password }}
|
||||
run: echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
- name: Setup Docker Trust
|
||||
if: |
|
||||
false
|
||||
&& (github.ref == 'refs/heads/master' ||
|
||||
github.ref == 'refs/heads/rc' ||
|
||||
github.ref == 'refs/heads/hotfix-rc')
|
||||
env:
|
||||
DCT_DELEGATION_KEY_ID: "c9bde8ec820701516491e5e03d3a6354e7bd66d05fa3df2b0062f68b116dc59c"
|
||||
DCT_DELEGATE_KEY: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-key }}
|
||||
DCT_REPO_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
run: |
|
||||
mkdir -p ~/.docker/trust/private
|
||||
echo "$DCT_DELEGATE_KEY" > ~/.docker/trust/private/$DCT_DELEGATION_KEY_ID.key
|
||||
echo "DOCKER_CONTENT_TRUST=1" >> $GITHUB_ENV
|
||||
echo "DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE=$DCT_REPO_PASSPHRASE" >> $GITHUB_ENV
|
||||
|
||||
- name: Tag and Push RC to Docker Hub
|
||||
if: |
|
||||
false
|
||||
&& (github.ref == 'refs/heads/master' ||
|
||||
github.ref == 'refs/heads/rc' ||
|
||||
github.ref == 'refs/heads/hotfix-rc')
|
||||
env:
|
||||
PROJECT_NAME: self-host
|
||||
REGISTRY: bitwarden
|
||||
run: |
|
||||
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name
|
||||
if [[ "$IMAGE_TAG" == "master" ]]; then
|
||||
IMAGE_TAG=dev
|
||||
fi
|
||||
|
||||
docker tag $PROJECT_NAME \
|
||||
$REGISTRY/$PROJECT_NAME:$IMAGE_TAG
|
||||
docker push $REGISTRY/$PROJECT_NAME:$IMAGE_TAG
|
||||
|
||||
- name: Log out of Docker and disable Docker Notary
|
||||
if: |
|
||||
false
|
||||
&& (github.ref == 'refs/heads/master' ||
|
||||
github.ref == 'refs/heads/rc' ||
|
||||
github.ref == 'refs/heads/hotfix-rc')
|
||||
run: |
|
||||
docker logout
|
||||
echo "DOCKER_CONTENT_TRUST=0" >> $GITHUB_ENV
|
||||
|
||||
check-failures:
|
||||
name: Check for failures
|
||||
if: always()
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build-docker
|
||||
steps:
|
||||
- name: Check if any job failed
|
||||
if: |
|
||||
github.ref == 'refs/heads/master'
|
||||
|| github.ref == 'refs/heads/rc'
|
||||
|| github.ref == 'refs/heads/hotfix-rc'
|
||||
env:
|
||||
BUILD_DOCKER_STATUS: ${{ needs.build-docker.result }}
|
||||
run: |
|
||||
if [ "$BUILD_DOCKER_STATUS" = "failure" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Login to Azure - Prod Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||
if: failure()
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af
|
||||
if: failure()
|
||||
with:
|
||||
keyvault: "bitwarden-prod-kv"
|
||||
secrets: "devops-alerts-slack-webhook-url"
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: act10ns/slack@da3191ebe2e67f49b46880b4633f5591a96d1d33
|
||||
if: failure()
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
|
135
.github/workflows/build.yml
vendored
135
.github/workflows/build.yml
vendored
@ -9,12 +9,11 @@ on:
|
||||
paths-ignore:
|
||||
- ".github/workflows/**"
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
|
||||
jobs:
|
||||
cloc:
|
||||
name: CLOC
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
|
||||
@ -29,7 +28,7 @@ jobs:
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
@ -83,7 +82,7 @@ jobs:
|
||||
|
||||
build-artifacts:
|
||||
name: Build artifacts
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- testing
|
||||
- lint
|
||||
@ -91,31 +90,31 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- service_name: Admin
|
||||
- project_name: Admin
|
||||
base_path: ./src
|
||||
node: true
|
||||
- service_name: Api
|
||||
- project_name: Api
|
||||
base_path: ./src
|
||||
- service_name: Billing
|
||||
- project_name: Billing
|
||||
base_path: ./src
|
||||
- service_name: Events
|
||||
- project_name: Events
|
||||
base_path: ./src
|
||||
- service_name: EventsProcessor
|
||||
- project_name: EventsProcessor
|
||||
base_path: ./src
|
||||
- service_name: Icons
|
||||
- project_name: Icons
|
||||
base_path: ./src
|
||||
- service_name: Identity
|
||||
- project_name: Identity
|
||||
base_path: ./src
|
||||
- service_name: Notifications
|
||||
- project_name: Notifications
|
||||
base_path: ./src
|
||||
- service_name: Server
|
||||
- project_name: Server
|
||||
base_path: ./util
|
||||
- service_name: Setup
|
||||
- project_name: Setup
|
||||
base_path: ./util
|
||||
- service_name: Sso
|
||||
- project_name: Sso
|
||||
base_path: ./bitwarden_license/src
|
||||
node: true
|
||||
- service_name: Scim
|
||||
- project_name: Scim
|
||||
base_path: ./bitwarden_license/src
|
||||
dotnet: true
|
||||
steps:
|
||||
@ -138,8 +137,8 @@ jobs:
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Restore/Clean service
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.service_name }}
|
||||
- name: Restore/Clean project
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
run: |
|
||||
echo "Restore"
|
||||
dotnet restore
|
||||
@ -148,92 +147,89 @@ jobs:
|
||||
|
||||
- name: Build node
|
||||
if: ${{ matrix.node }}
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.service_name }}
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Publish service
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.service_name }}
|
||||
- name: Publish project
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
run: |
|
||||
echo "Publish"
|
||||
dotnet publish -c "Release" -o obj/build-output/publish
|
||||
|
||||
cd obj/build-output/publish
|
||||
zip -r ${{ matrix.service_name }}.zip .
|
||||
mv ${{ matrix.service_name }}.zip ../../../
|
||||
zip -r ${{ matrix.project_name }}.zip .
|
||||
mv ${{ matrix.project_name }}.zip ../../../
|
||||
|
||||
pwd
|
||||
ls -atlh ../../../
|
||||
|
||||
- name: Upload service artifact
|
||||
- name: Upload project artifact
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
with:
|
||||
name: ${{ matrix.service_name }}.zip
|
||||
path: ${{ matrix.base_path }}/${{ matrix.service_name }}/${{ matrix.service_name }}.zip
|
||||
name: ${{ matrix.project_name }}.zip
|
||||
path: ${{ matrix.base_path }}/${{ matrix.project_name }}/${{ matrix.project_name }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
build-docker:
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build-artifacts
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- service_name: Admin
|
||||
- project_name: Admin
|
||||
base_path: ./src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Api
|
||||
- project_name: Api
|
||||
base_path: ./src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Attachments
|
||||
- project_name: Attachments
|
||||
base_path: ./util
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
- service_name: Events
|
||||
- project_name: Events
|
||||
base_path: ./src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: EventsProcessor
|
||||
- project_name: EventsProcessor
|
||||
base_path: ./src
|
||||
docker_repos: [bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Icons
|
||||
- project_name: Icons
|
||||
base_path: ./src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Identity
|
||||
- project_name: Identity
|
||||
base_path: ./src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: K8S-Proxy
|
||||
- project_name: MsSql
|
||||
base_path: ./util
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
- service_name: MsSql
|
||||
- project_name: Nginx
|
||||
base_path: ./util
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
- service_name: Nginx
|
||||
base_path: ./util
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
- service_name: Notifications
|
||||
- project_name: Notifications
|
||||
base_path: ./src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Server
|
||||
- project_name: Server
|
||||
base_path: ./util
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Setup
|
||||
- project_name: Setup
|
||||
base_path: ./util
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Sso
|
||||
- project_name: Sso
|
||||
base_path: ./bitwarden_license/src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
- service_name: Scim
|
||||
- project_name: Scim
|
||||
base_path: ./bitwarden_license/src
|
||||
docker_repos: [bitwarden, bitwardenqa.azurecr.io]
|
||||
dotnet: true
|
||||
@ -243,36 +239,31 @@ jobs:
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
|
||||
########## Build Docker Image ##########
|
||||
- name: Setup service name
|
||||
- name: Setup project name
|
||||
id: setup
|
||||
run: |
|
||||
SERVICE_NAME=$(echo "${{ matrix.service_name }}" | awk '{print tolower($0)}')
|
||||
echo "Matrix name: ${{ matrix.service_name }}"
|
||||
echo "SERVICE_NAME: $SERVICE_NAME"
|
||||
echo "::set-output name=service_name::$SERVICE_NAME"
|
||||
PROJECT_NAME=$(echo "${{ matrix.project_name }}" | awk '{print tolower($0)}')
|
||||
echo "Matrix name: ${{ matrix.project_name }}"
|
||||
echo "PROJECT_NAME: $PROJECT_NAME"
|
||||
echo "::set-output name=project_name::$PROJECT_NAME"
|
||||
|
||||
- name: Get build artifact
|
||||
if: ${{ matrix.dotnet }}
|
||||
uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741
|
||||
with:
|
||||
name: ${{ matrix.service_name }}.zip
|
||||
name: ${{ matrix.project_name }}.zip
|
||||
|
||||
- name: Setup build artifact
|
||||
if: ${{ matrix.dotnet }}
|
||||
run: |
|
||||
mkdir -p ${{ matrix.base_path}}/${{ matrix.service_name }}/obj/build-output/publish
|
||||
unzip ${{ matrix.service_name }}.zip \
|
||||
-d ${{ matrix.base_path }}/${{ matrix.service_name }}/obj/build-output/publish
|
||||
mkdir -p ${{ matrix.base_path}}/${{ matrix.project_name }}/obj/build-output/publish
|
||||
unzip ${{ matrix.project_name }}.zip \
|
||||
-d ${{ matrix.base_path }}/${{ matrix.project_name }}/obj/build-output/publish
|
||||
|
||||
- name: Build Docker images
|
||||
run: |
|
||||
if [ "${{ matrix.service_name }}" = "K8S-Proxy" ]; then
|
||||
docker build -f ${{ matrix.base_path }}/Nginx/Dockerfile-k8s \
|
||||
-t ${{ steps.setup.outputs.service_name }} ${{ matrix.base_path }}/Nginx
|
||||
else
|
||||
docker build -t ${{ steps.setup.outputs.service_name }} \
|
||||
${{ matrix.base_path }}/${{ matrix.service_name }}
|
||||
fi
|
||||
- name: Build Docker image
|
||||
env:
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
run: docker build -t $PROJECT_NAME ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
|
||||
########## ACR ##########
|
||||
- name: Login to Azure - QA Subscription
|
||||
@ -283,8 +274,9 @@ jobs:
|
||||
- name: Login to Azure ACR
|
||||
run: az acr login -n bitwardenqa
|
||||
|
||||
- name: Tag and Push RC to Azure ACR QA registry
|
||||
- name: Tag and Push image to Azure ACR QA registry
|
||||
env:
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
REGISTRY: bitwardenqa.azurecr.io
|
||||
run: |
|
||||
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name
|
||||
@ -292,9 +284,9 @@ jobs:
|
||||
IMAGE_TAG=dev
|
||||
fi
|
||||
|
||||
docker tag ${{ steps.setup.outputs.service_name }} \
|
||||
$REGISTRY/${{ steps.setup.outputs.service_name }}:$IMAGE_TAG
|
||||
docker push $REGISTRY/${{ steps.setup.outputs.service_name }}:$IMAGE_TAG
|
||||
docker tag $PROJECT_NAME \
|
||||
$REGISTRY/$PROJECT_NAME:$IMAGE_TAG
|
||||
docker push $REGISTRY/$PROJECT_NAME:$IMAGE_TAG
|
||||
|
||||
- name: Log out of Docker
|
||||
run: docker logout
|
||||
@ -360,6 +352,7 @@ jobs:
|
||||
github.ref == 'refs/heads/rc' ||
|
||||
github.ref == 'refs/heads/hotfix-rc')
|
||||
env:
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
REGISTRY: bitwarden
|
||||
run: |
|
||||
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name
|
||||
@ -367,9 +360,9 @@ jobs:
|
||||
IMAGE_TAG=dev
|
||||
fi
|
||||
|
||||
docker tag ${{ steps.setup.outputs.service_name }} \
|
||||
$REGISTRY/${{ steps.setup.outputs.service_name }}:$IMAGE_TAG
|
||||
docker push $REGISTRY/${{ steps.setup.outputs.service_name }}:$IMAGE_TAG
|
||||
docker tag $PROJECT_NAME \
|
||||
$REGISTRY/$PROJECT_NAME:$IMAGE_TAG
|
||||
docker push $REGISTRY/$PROJECT_NAME:$IMAGE_TAG
|
||||
|
||||
- name: Log out of Docker and disable Docker Notary
|
||||
if: |
|
||||
@ -383,7 +376,7 @@ jobs:
|
||||
|
||||
upload:
|
||||
name: Upload
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build-docker
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
@ -462,7 +455,7 @@ jobs:
|
||||
check-failures:
|
||||
name: Check for failures
|
||||
if: always()
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- cloc
|
||||
- lint
|
||||
|
144
.github/workflows/release.yml
vendored
144
.github/workflows/release.yml
vendored
@ -6,20 +6,19 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Release Options'
|
||||
description: "Release Options"
|
||||
required: true
|
||||
default: 'Initial Release'
|
||||
default: "Initial Release"
|
||||
type: choice
|
||||
options:
|
||||
- Initial Release
|
||||
- Redeploy
|
||||
- Dry Run
|
||||
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
name: Setup
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
release_version: ${{ steps.version.outputs.version }}
|
||||
branch-name: ${{ steps.branch.outputs.branch-name }}
|
||||
@ -51,10 +50,9 @@ jobs:
|
||||
BRANCH_NAME=$(basename ${{ github.ref }})
|
||||
echo "::set-output name=branch-name::$BRANCH_NAME"
|
||||
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- setup
|
||||
strategy:
|
||||
@ -81,11 +79,11 @@ jobs:
|
||||
uses: chrnorm/deployment-action@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
|
||||
id: deployment
|
||||
with:
|
||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
initial-status: 'in_progress'
|
||||
environment: 'Production Cloud'
|
||||
task: 'deploy'
|
||||
description: 'Deploy from ${{ needs.setup.outputs.branch-name }} branch'
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
initial-status: "in_progress"
|
||||
environment: "Production Cloud"
|
||||
task: "deploy"
|
||||
description: "Deploy from ${{ needs.setup.outputs.branch-name }} branch"
|
||||
|
||||
- name: Download latest Release ${{ matrix.name }} asset
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
@ -155,22 +153,21 @@ jobs:
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }}
|
||||
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
|
||||
with:
|
||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
state: 'success'
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
state: "success"
|
||||
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
|
||||
|
||||
- name: Update ${{ matrix.name }} deployment status to Failure
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }}
|
||||
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
|
||||
with:
|
||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
state: 'failure'
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
state: "failure"
|
||||
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
|
||||
|
||||
|
||||
release-docker:
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- setup
|
||||
env:
|
||||
@ -180,38 +177,36 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- service_name: Admin
|
||||
- project_name: Admin
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Api
|
||||
- project_name: Api
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Attachments
|
||||
- project_name: Attachments
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Events
|
||||
- project_name: Events
|
||||
prod_acr: true
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: EventsProcessor
|
||||
- project_name: EventsProcessor
|
||||
prod_acr: true
|
||||
origin_docker_repo: bitwardenqa.azurecr.io
|
||||
- service_name: Icons
|
||||
- project_name: Icons
|
||||
origin_docker_repo: bitwarden
|
||||
prod_acr: true
|
||||
- service_name: Identity
|
||||
- project_name: Identity
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: K8S-Proxy
|
||||
- project_name: MsSql
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: MsSql
|
||||
- project_name: Nginx
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Nginx
|
||||
- project_name: Notifications
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Notifications
|
||||
- project_name: Server
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Server
|
||||
- project_name: Setup
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Setup
|
||||
- project_name: Sso
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Sso
|
||||
origin_docker_repo: bitwarden
|
||||
- service_name: Scim
|
||||
- project_name: Scim
|
||||
origin_docker_repo: bitwarden
|
||||
skip_dct: true
|
||||
steps:
|
||||
@ -228,13 +223,13 @@ jobs:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
||||
|
||||
- name: Setup service name
|
||||
- name: Setup project name
|
||||
id: setup
|
||||
run: |
|
||||
SERVICE_NAME=$(echo "${{ matrix.service_name }}" | awk '{print tolower($0)}')
|
||||
echo "Matrix name: ${{ matrix.service_name }}"
|
||||
echo "SERVICE_NAME: $SERVICE_NAME"
|
||||
echo "::set-output name=service_name::$SERVICE_NAME"
|
||||
PROJECT_NAME=$(echo "${{ matrix.project_name }}" | awk '{print tolower($0)}')
|
||||
echo "Matrix name: ${{ matrix.project_name }}"
|
||||
echo "PROJECT_NAME: $PROJECT_NAME"
|
||||
echo "::set-output name=project_name::$PROJECT_NAME"
|
||||
|
||||
########## DockerHub ##########
|
||||
- name: Setup DCT
|
||||
@ -255,26 +250,26 @@ jobs:
|
||||
echo "::set-output name=dct_enabled::1"
|
||||
fi
|
||||
|
||||
- name: Pull latest selfhost image
|
||||
- name: Pull latest project image
|
||||
if: matrix.origin_docker_repo == 'bitwarden'
|
||||
env:
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker pull bitwarden/$SERVICE_NAME:latest
|
||||
docker pull bitwarden/$PROJECT_NAME:latest
|
||||
else
|
||||
docker pull bitwarden/$SERVICE_NAME:$_BRANCH_NAME
|
||||
docker pull bitwarden/$PROJECT_NAME:$_BRANCH_NAME
|
||||
fi
|
||||
|
||||
- name: Tag version and latest
|
||||
if: matrix.origin_docker_repo == 'bitwarden'
|
||||
env:
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker tag bitwarden/$SERVICE_NAME:latest bitwarden/$SERVICE_NAME:dryrun
|
||||
docker tag bitwarden/$PROJECT_NAME:latest bitwarden/$PROJECT_NAME:dryrun
|
||||
else
|
||||
docker tag bitwarden/$SERVICE_NAME:$_BRANCH_NAME bitwarden/$SERVICE_NAME:$_RELEASE_VERSION
|
||||
docker tag bitwarden/$PROJECT_NAME:$_BRANCH_NAME bitwarden/$PROJECT_NAME:$_RELEASE_VERSION
|
||||
fi
|
||||
|
||||
- name: Push version and latest image
|
||||
@ -282,8 +277,8 @@ jobs:
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: ${{ steps.check-matrix-dct.outputs.dct_enabled }}
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
run: docker push bitwarden/$SERVICE_NAME:$_RELEASE_VERSION
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
run: docker push bitwarden/$PROJECT_NAME:$_RELEASE_VERSION
|
||||
|
||||
- name: Log out of Docker and disable Docker Notary
|
||||
if: matrix.origin_docker_repo == 'bitwarden'
|
||||
@ -300,36 +295,39 @@ jobs:
|
||||
- name: Login to Azure ACR
|
||||
run: az acr login -n bitwardenqa
|
||||
|
||||
- name: Pull latest selfhost image
|
||||
- name: Pull latest project image
|
||||
if: matrix.origin_docker_repo == 'bitwardenqa.azurecr.io'
|
||||
env:
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
REGISTRY: bitwardenqa.azurecr.io
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker pull $REGISTRY/$SERVICE_NAME:latest
|
||||
docker pull $REGISTRY/$PROJECT_NAME:latest
|
||||
else
|
||||
docker pull $REGISTRY/$SERVICE_NAME:$_BRANCH_NAME
|
||||
docker pull $REGISTRY/$PROJECT_NAME:$_BRANCH_NAME
|
||||
fi
|
||||
|
||||
- name: Tag version and latest
|
||||
env:
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
REGISTRY: bitwardenqa.azurecr.io
|
||||
ORIGIN_REGISTY: ${{ matrix.origin_docker_repo }}
|
||||
ORIGIN_REGISTRY: ${{ matrix.origin_docker_repo }}
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker tag $ORIGIN_REGISTY/$SERVICE_NAME:latest $REGISTRY/$SERVICE_NAME:dryrun
|
||||
docker tag $ORIGIN_REGISTRY/$PROJECT_NAME:latest $REGISTRY/$PROJECT_NAME:dryrun
|
||||
else
|
||||
docker tag $ORIGIN_REGISTY/$SERVICE_NAME:$_BRANCH_NAME $REGISTRY/$SERVICE_NAME:$_RELEASE_VERSION
|
||||
docker tag $ORIGIN_REGISTRY/$PROJECT_NAME:$_BRANCH_NAME $REGISTRY/$PROJECT_NAME:$_RELEASE_VERSION
|
||||
docker tag $ORIGIN_REGISTRY/$PROJECT_NAME:$_BRANCH_NAME $REGISTRY/$PROJECT_NAME:latest
|
||||
fi
|
||||
|
||||
- name: Push version and latest image
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
env:
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
REGISTRY: bitwardenqa.azurecr.io
|
||||
run: docker push $REGISTRY/$SERVICE_NAME:$_RELEASE_VERSION
|
||||
run: |
|
||||
docker push $REGISTRY/$PROJECT_NAME:latest
|
||||
docker push $REGISTRY/$PROJECT_NAME:$_RELEASE_VERSION
|
||||
|
||||
- name: Log out of Docker
|
||||
run: docker logout
|
||||
@ -348,31 +346,33 @@ jobs:
|
||||
- name: Tag version and latest
|
||||
if: matrix.prod_acr == true
|
||||
env:
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
REGISTRY: bitwardenprod.azurecr.io
|
||||
ORIGIN_REGISTY: ${{ matrix.origin_docker_repo }}
|
||||
ORIGIN_REGISTRY: ${{ matrix.origin_docker_repo }}
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker tag $ORIGIN_REGISTY/$SERVICE_NAME:latest $REGISTRY/$SERVICE_NAME:dryrun
|
||||
docker tag $ORIGIN_REGISTRY/$PROJECT_NAME:latest $REGISTRY/$PROJECT_NAME:dryrun
|
||||
else
|
||||
docker tag $ORIGIN_REGISTY/$SERVICE_NAME:$_BRANCH_NAME $REGISTRY/$SERVICE_NAME:$_RELEASE_VERSION
|
||||
docker tag $ORIGIN_REGISTRY/$PROJECT_NAME:$_BRANCH_NAME $REGISTRY/$PROJECT_NAME:$_RELEASE_VERSION
|
||||
docker tag $ORIGIN_REGISTRY/$PROJECT_NAME:$_BRANCH_NAME $REGISTRY/$PROJECT_NAME:latest
|
||||
fi
|
||||
|
||||
- name: Push version and latest image
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' && matrix.prod_acr == true }}
|
||||
env:
|
||||
SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
|
||||
PROJECT_NAME: ${{ steps.setup.outputs.project_name }}
|
||||
REGISTRY: bitwardenprod.azurecr.io
|
||||
run: docker push $REGISTRY/$SERVICE_NAME:$_RELEASE_VERSION
|
||||
run: |
|
||||
docker push $REGISTRY/$PROJECT_NAME:$_RELEASE_VERSION
|
||||
docker push $REGISTRY/$PROJECT_NAME:latest
|
||||
|
||||
- name: Log out of Docker
|
||||
if: matrix.prod_acr == true
|
||||
run: docker logout
|
||||
|
||||
|
||||
release:
|
||||
name: Create GitHub Release
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- setup
|
||||
- deploy
|
||||
@ -385,8 +385,8 @@ jobs:
|
||||
workflow_conclusion: success
|
||||
branch: ${{ needs.setup.outputs.branch-name }}
|
||||
artifacts: "docker-stub.zip,
|
||||
docker-stub-sha256.txt,
|
||||
swagger.json"
|
||||
docker-stub-sha256.txt,
|
||||
swagger.json"
|
||||
|
||||
- name: Download latest Release docker-stub
|
||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||
@ -396,16 +396,16 @@ jobs:
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
artifacts: "docker-stub.zip,
|
||||
docker-stub-sha256.txt,
|
||||
swagger.json"
|
||||
docker-stub-sha256.txt,
|
||||
swagger.json"
|
||||
|
||||
- name: Create release
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01
|
||||
with:
|
||||
artifacts: 'docker-stub.zip,
|
||||
docker-stub-sha256.txt,
|
||||
swagger.json'
|
||||
artifacts: "docker-stub.zip,
|
||||
docker-stub-sha256.txt,
|
||||
swagger.json"
|
||||
commit: ${{ github.sha }}
|
||||
tag: "v${{ needs.setup.outputs.release_version }}"
|
||||
name: "Version ${{ needs.setup.outputs.release_version }}"
|
||||
|
@ -40,7 +40,7 @@ public class Startup
|
||||
StripeConfiguration.MaxNetworkRetries = globalSettings.Stripe.MaxNetworkRetries;
|
||||
|
||||
// Repositories
|
||||
services.AddSqlServerRepositories(globalSettings);
|
||||
services.AddDatabaseRepositories(globalSettings);
|
||||
|
||||
// Context
|
||||
services.AddScoped<ICurrentContext, CurrentContext>();
|
||||
|
@ -37,7 +37,7 @@ public class Startup
|
||||
services.AddCustomDataProtectionServices(Environment, globalSettings);
|
||||
|
||||
// Repositories
|
||||
services.AddSqlServerRepositories(globalSettings);
|
||||
services.AddDatabaseRepositories(globalSettings);
|
||||
|
||||
// Context
|
||||
services.AddScoped<ICurrentContext, CurrentContext>();
|
||||
|
3
docker-unified/.env.example
Normal file
3
docker-unified/.env.example
Normal file
@ -0,0 +1,3 @@
|
||||
COMPOSE_PROJECT_NAME=bitwarden
|
||||
REGISTRY=bitwarden
|
||||
TAG=dev
|
291
docker-unified/Dockerfile
Normal file
291
docker-unified/Dockerfile
Normal file
@ -0,0 +1,291 @@
|
||||
###############################################
|
||||
# Build stage #
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM alpine AS web-setup
|
||||
|
||||
# Add packages
|
||||
RUN apk add --update-cache \
|
||||
curl \
|
||||
jq \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
# Download tags from 'clients' repository
|
||||
RUN curl https://api.github.com/repos/bitwarden/clients/git/refs/tags --output tags.json
|
||||
|
||||
# Grab last tag/release of the 'web' client
|
||||
RUN cat tags.json | jq -r 'last(.[] | select(.ref|test("refs/tags/web-v[0-9]{4}.[0-9]{1,2}.[0-9]+"))) | .ref | split("/")[2]' > tag.txt
|
||||
|
||||
# Extract the version of the 'web' client
|
||||
RUN cat tag.txt | grep -o -E "[0-9]{4}\.[0-9]{1,2}\.[0-9]+" > version.txt
|
||||
|
||||
# Download the built release artifact for the 'web' client
|
||||
RUN TAG=$(cat tag.txt) \
|
||||
&& VERSION=$(cat version.txt) \
|
||||
&& curl -L https://github.com/bitwarden/clients/releases/download/$TAG/web-$VERSION-selfhosted-COMMERCIAL.zip -O
|
||||
|
||||
# Unzip the 'web' client to /tmp/build
|
||||
RUN VERSION=$(cat version.txt) \
|
||||
&& unzip web-$VERSION-selfhosted-COMMERCIAL.zip
|
||||
|
||||
###############################################
|
||||
# Build stage #
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:6.0 AS dotnet-build
|
||||
|
||||
# Docker buildx supplies the value for this arg
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Determine proper runtime value for .NET
|
||||
# We put the value in a file to be read by later layers.
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
RID=linux-x64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
RID=linux-arm64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \
|
||||
RID=linux-arm ; \
|
||||
fi \
|
||||
&& echo "RID=$RID" > /tmp/rid.txt
|
||||
|
||||
# Add packages
|
||||
# RUN apk add --update-cache \
|
||||
# npm \
|
||||
# && rm -rf /var/cache/apk/*
|
||||
RUN apt-get update && apt-get install -y \
|
||||
npm \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN npm install -g gulp
|
||||
|
||||
# Copy csproj files as distinct layers
|
||||
WORKDIR /source
|
||||
COPY src/Admin/*.csproj ./src/Admin/
|
||||
COPY src/Api/*.csproj ./src/Api/
|
||||
COPY src/Events/*.csproj ./src/Events/
|
||||
COPY src/Icons/*.csproj ./src/Icons/
|
||||
COPY src/Identity/*.csproj ./src/Identity/
|
||||
COPY src/Notifications/*.csproj ./src/Notifications/
|
||||
COPY bitwarden_license/src/Sso/*.csproj ./bitwarden_license/src/Sso/
|
||||
COPY bitwarden_license/src/Scim/*.csproj ./bitwarden_license/src/Scim/
|
||||
COPY src/Core/*.csproj ./src/Core/
|
||||
COPY src/Infrastructure.Dapper/*.csproj ./src/Infrastructure.Dapper/
|
||||
COPY src/Infrastructure.EntityFramework/*.csproj ./src/Infrastructure.EntityFramework/
|
||||
COPY src/SharedWeb/*.csproj ./src/SharedWeb/
|
||||
COPY util/Migrator/*.csproj ./util/Migrator/
|
||||
COPY util/MySqlMigrations/*.csproj ./util/MySqlMigrations/
|
||||
COPY util/PostgresMigrations/*.csproj ./util/PostgresMigrations/
|
||||
COPY bitwarden_license/src/Commercial.Core/*.csproj ./bitwarden_license/src/Commercial.Core/
|
||||
COPY Directory.Build.props .
|
||||
|
||||
# Restore Admin project dependencies and tools
|
||||
WORKDIR /source/src/Admin
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Restore Api project dependencies and tools
|
||||
WORKDIR /source/src/Api
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Restore Events project dependencies and tools
|
||||
WORKDIR /source/src/Events
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Restore Icons project dependencies and tools
|
||||
WORKDIR /source/src/Icons
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Restore Identity project dependencies and tools
|
||||
WORKDIR /source/src/Identity
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Restore Notifications project dependencies and tools
|
||||
WORKDIR /source/src/Notifications
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Restore Sso project dependencies and tools
|
||||
WORKDIR /source/bitwarden_license/src/Sso
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Restore Scim project dependencies and tools
|
||||
WORKDIR /source/bitwarden_license/src/Scim
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Copy required project files
|
||||
WORKDIR /source
|
||||
COPY src/Admin/. ./src/Admin/
|
||||
COPY src/Api/. ./src/Api/
|
||||
COPY src/Events/. ./src/Events/
|
||||
COPY src/Icons/. ./src/Icons/
|
||||
COPY src/Identity/. ./src/Identity/
|
||||
COPY src/Notifications/. ./src/Notifications/
|
||||
COPY bitwarden_license/src/Sso/. ./bitwarden_license/src/Sso/
|
||||
COPY bitwarden_license/src/Scim/. ./bitwarden_license/src/Scim/
|
||||
COPY src/Core/. ./src/Core/
|
||||
COPY src/Infrastructure.Dapper/. ./src/Infrastructure.Dapper/
|
||||
COPY src/Infrastructure.EntityFramework/. ./src/Infrastructure.EntityFramework/
|
||||
COPY src/SharedWeb/. ./src/SharedWeb/
|
||||
COPY util/Migrator/. ./util/Migrator/
|
||||
COPY util/MySqlMigrations/. ./util/MySqlMigrations/
|
||||
COPY util/PostgresMigrations/. ./util/PostgresMigrations/
|
||||
COPY util/EfShared/. ./util/EfShared/
|
||||
COPY bitwarden_license/src/Commercial.Core/. ./bitwarden_license/src/Commercial.Core/
|
||||
COPY .git/. ./.git/
|
||||
|
||||
# Build Admin app
|
||||
WORKDIR /source/src/Admin
|
||||
RUN npm install
|
||||
RUN gulp --gulpfile "gulpfile.js" build
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Admin --no-restore --no-self-contained -r $RID
|
||||
|
||||
# Build Api app
|
||||
WORKDIR /source/src/Api
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Api --no-restore --no-self-contained -r $RID
|
||||
|
||||
# Build Events app
|
||||
WORKDIR /source/src/Events
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Events --no-restore --no-self-contained -r $RID
|
||||
|
||||
# Build Icons app
|
||||
WORKDIR /source/src/Icons
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Icons --no-restore --no-self-contained -r $RID
|
||||
|
||||
# Build Identity app
|
||||
WORKDIR /source/src/Identity
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Identity --no-restore --no-self-contained -r $RID
|
||||
|
||||
# Build Notifications app
|
||||
WORKDIR /source/src/Notifications
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Notifications --no-restore --no-self-contained -r $RID
|
||||
|
||||
# Build Sso app
|
||||
WORKDIR /source/bitwarden_license/src/Sso
|
||||
RUN npm install
|
||||
RUN gulp --gulpfile "gulpfile.js" build
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Sso --no-restore --no-self-contained -r $RID
|
||||
|
||||
# Build Scim app
|
||||
WORKDIR /source/bitwarden_license/src/Scim
|
||||
RUN . /tmp/rid.txt && dotnet publish -c release -o /app/Scim --no-restore --no-self-contained -r $RID
|
||||
|
||||
###############################################
|
||||
# App stage #
|
||||
###############################################
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine
|
||||
ARG TARGETPLATFORM
|
||||
LABEL com.bitwarden.product="bitwarden"
|
||||
LABEL com.bitwarden.project="unified"
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV BW_ENABLE_ADMIN=true
|
||||
ENV BW_ENABLE_API=true
|
||||
ENV BW_ENABLE_EVENTS=false
|
||||
ENV BW_ENABLE_ICONS=true
|
||||
ENV BW_ENABLE_IDENTITY=true
|
||||
ENV BW_ENABLE_NOTIFICATIONS=true
|
||||
ENV BW_ENABLE_SCIM=false
|
||||
ENV BW_ENABLE_SSO=false
|
||||
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
|
||||
ENV globalSettings__selfHosted="true"
|
||||
ENV globalSettings__pushRelayBaseUri="https://push.bitwarden.com"
|
||||
ENV globalSettings__baseServiceUri__internalAdmin="http://localhost:5000"
|
||||
ENV globalSettings__baseServiceUri__internalApi="http://localhost:5001"
|
||||
ENV globalSettings__baseServiceUri__internalEvents="http://localhost:5003"
|
||||
ENV globalSettings__baseServiceUri__internalIcons="http://localhost:5004"
|
||||
ENV globalSettings__baseServiceUri__internalIdentity="http://localhost:5005"
|
||||
ENV globalSettings__baseServiceUri__internalNotifications="http://localhost:5006"
|
||||
ENV globalSettings__baseServiceUri__internalSso="http://localhost:5007"
|
||||
ENV globalSettings__baseServiceUri__internalScim="http://localhost:5002"
|
||||
ENV globalSettings__baseServiceUri__internalVault="http://localhost:80"
|
||||
ENV globalSettings__identityServer__certificatePassword="default_cert_password"
|
||||
ENV globalSettings__dataProtection__directory="/etc/bitwarden/data-protection"
|
||||
ENV globalSettings__attachment__baseDirectory="/etc/bitwarden/attachments"
|
||||
ENV globalSettings__send__baseDirectory="/etc/bitwarden/attachments/send"
|
||||
ENV globalSettings__licenseDirectory="/etc/bitwarden/licenses"
|
||||
ENV globalSettings__logDirectoryByProject="false"
|
||||
ENV globalSettings__logRollBySizeLimit="1073741824"
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
# Add packages
|
||||
RUN apk add --update-cache \
|
||||
curl \
|
||||
icu-libs \
|
||||
nginx \
|
||||
openssl \
|
||||
su-exec \
|
||||
supervisor \
|
||||
tzdata \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Create non-root user to run app
|
||||
RUN adduser -s /bin/false -D bitwarden
|
||||
|
||||
# Create required directories
|
||||
RUN mkdir -p /etc/bitwarden/attachments/send
|
||||
RUN mkdir -p /etc/bitwarden/data-protection
|
||||
RUN mkdir -p /etc/bitwarden/licenses
|
||||
RUN mkdir -p /etc/bitwarden/logs
|
||||
RUN mkdir -p /etc/supervisor
|
||||
RUN mkdir -p /etc/supervisor.d
|
||||
RUN mkdir -p /var/log/bitwarden
|
||||
RUN mkdir -p /var/log/nginx/logs
|
||||
RUN mkdir -p /app
|
||||
RUN chown -R bitwarden:bitwarden \
|
||||
/app \
|
||||
/etc/bitwarden \
|
||||
/etc/nginx/http.d \
|
||||
/etc/supervisor \
|
||||
/etc/supervisor.d \
|
||||
/var/lib/nginx \
|
||||
/var/log \
|
||||
/run
|
||||
|
||||
# Copy all apps from dotnet-build stage
|
||||
WORKDIR /app
|
||||
COPY --chown=bitwarden:bitwarden --from=dotnet-build /app ./
|
||||
|
||||
# Copy Web files from web-setup stage
|
||||
COPY --chown=bitwarden:bitwarden --from=web-setup /tmp/build /app/Web
|
||||
|
||||
# Set up supervisord
|
||||
COPY --chown=bitwarden:bitwarden docker-unified/supervisord/*.ini /etc/supervisor.d/
|
||||
COPY --chown=bitwarden:bitwarden docker-unified/supervisord/supervisord.conf /etc/supervisor/supervisord.conf
|
||||
RUN rm -f /etc/supervisord.conf
|
||||
|
||||
# Set up nginx
|
||||
COPY docker-unified/nginx/nginx.conf /etc/nginx
|
||||
COPY docker-unified/nginx/proxy.conf /etc/nginx
|
||||
COPY docker-unified/nginx/mime.types /etc/nginx
|
||||
COPY docker-unified/nginx/security-headers.conf /etc/nginx
|
||||
COPY docker-unified/nginx/security-headers-ssl.conf /etc/nginx
|
||||
COPY docker-unified/nginx/logrotate.sh /
|
||||
RUN chmod +x /logrotate.sh
|
||||
|
||||
# Copy configuration templates
|
||||
COPY docker-unified/confd/nginx-config.toml /etc/confd/conf.d/
|
||||
COPY docker-unified/confd/nginx-config.conf.tmpl /etc/confd/templates/
|
||||
COPY docker-unified/confd/app-id.toml /etc/confd/conf.d/
|
||||
COPY docker-unified/confd/app-id.conf.tmpl /etc/confd/templates/
|
||||
|
||||
# Download confd tool for generating final configurations
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ] ; then curl -L --output confd.tar.gz https://github.com/abtreece/confd/releases/download/v0.19.1/confd-v0.19.1-linux-amd64.tar.gz; fi
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/arm/v7" ] ; then curl -L --output confd.tar.gz https://github.com/abtreece/confd/releases/download/v0.19.1/confd-v0.19.1-linux-arm7.tar.gz; fi
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ] ; then curl -L --output confd.tar.gz https://github.com/abtreece/confd/releases/download/v0.19.1/confd-v0.19.1-linux-arm64.tar.gz; fi
|
||||
|
||||
# Extract confd
|
||||
RUN tar -xvzo -C /usr/local/bin -f confd.tar.gz && rm confd.tar.gz
|
||||
|
||||
# Copy entrypoint script and make it executable
|
||||
COPY docker-unified/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# TODO: Remove after testing
|
||||
RUN apk add --update-cache \
|
||||
vim \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
VOLUME ["/etc/bitwarden"]
|
||||
|
||||
WORKDIR /app
|
||||
USER bitwarden:bitwarden
|
||||
HEALTHCHECK CMD curl --insecure -Lfs https://localhost/alive || curl -Lfs http://localhost/alive || exit 1
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
15
docker-unified/confd/app-id.conf.tmpl
Normal file
15
docker-unified/confd/app-id.conf.tmpl
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"trustedFacets": [
|
||||
{
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"ids": [
|
||||
"{{ getenv "globalSettings__baseServiceUri__vault" "https://localhost" }}",
|
||||
"ios:bundle-id:com.8bit.bitwarden",
|
||||
"android:apk-key-hash:dUGFzUzf3lmHSLBDBIv+WaFyZMI"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
6
docker-unified/confd/app-id.toml
Normal file
6
docker-unified/confd/app-id.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[template]
|
||||
src = "app-id.conf.tmpl"
|
||||
dest = "/app/Web/app-id.json"
|
||||
keys = [
|
||||
"globalSettings__baseServiceUri__vault"
|
||||
]
|
144
docker-unified/confd/nginx-config.conf.tmpl
Normal file
144
docker-unified/confd/nginx-config.conf.tmpl
Normal file
@ -0,0 +1,144 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
#listen [::]:80 default_server;
|
||||
server_name {{ getenv "BW_DOMAIN" "localhost" }};
|
||||
{{ if eq (getenv "BW_ENABLE_SSL") "true" }}
|
||||
|
||||
return 301 https://{{ getenv "BW_DOMAIN" "localhost" }}$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
#listen [::]:443 ssl http2;
|
||||
server_name {{ getenv "BW_DOMAIN" "localhost" }};
|
||||
|
||||
ssl_certificate /etc/bitwarden/{{ getenv "BW_SSL_CERT" "ssl.crt" }};
|
||||
ssl_certificate_key /etc/bitwarden/{{ getenv "BW_SSL_KEY" "ssl.key" }};
|
||||
ssl_session_timeout 30m;
|
||||
ssl_session_cache shared:SSL:20m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
ssl_protocols {{ getenv "BW_SSL_PROTOCOLS" "TLSv1.2" }};
|
||||
ssl_ciphers "{{ getenv "BW_SSL_CIPHERS" "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256" }}";
|
||||
# Enables server-side protection from BEAST attacks
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ if eq (getenv "BW_ENABLE_SSL_CA") "true" }}
|
||||
|
||||
# OCSP Stapling ---
|
||||
# Fetch OCSP records from URL in ssl_certificate and cache them
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# Verify chain of trust of OCSP response using Root CA and Intermediate certs
|
||||
ssl_trusted_certificate /etc/bitwarden/{{ getenv "BW_SSL_CA_CERT" "ca.crt" }};
|
||||
resolver 1.1.1.1 1.0.0.1 9.9.9.9 149.112.112.112 valid=300s;
|
||||
{{ end }}
|
||||
|
||||
include /etc/nginx/security-headers-ssl.conf;
|
||||
{{ end }}
|
||||
include /etc/nginx/security-headers.conf;
|
||||
{{ if getenv "BW_REAL_IPS" }}
|
||||
|
||||
{{ range (getenv "BW_REAL_IPS") }}
|
||||
set_real_ip_from {{ .Key }};
|
||||
{{ end }}
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
{{ end }}
|
||||
|
||||
location / {
|
||||
root /app/Web;
|
||||
{{ if eq (getenv "BW_ENABLE_SSL") "true" }}
|
||||
include /etc/nginx/security-headers-ssl.conf;
|
||||
{{ end }}
|
||||
include /etc/nginx/security-headers.conf;
|
||||
add_header Content-Security-Policy "{{ getenv "BW_CSP" "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com https://www.gravatar.com; child-src 'self' https://*.duosecurity.com https://*.duofederal.com; frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; connect-src 'self' https://api.pwnedpasswords.com https://2fa.directory; object-src 'self' blob:;" }}";
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
add_header X-Robots-Tag "noindex, nofollow";
|
||||
}
|
||||
|
||||
location /alive {
|
||||
default_type text/plain;
|
||||
return 200 $date_gmt;
|
||||
}
|
||||
|
||||
location = /app-id.json {
|
||||
root /app/Web;
|
||||
{{ if eq (getenv "BW_ENABLE_SSL") "true" }}
|
||||
include /etc/nginx/security-headers-ssl.conf;
|
||||
{{ end }}
|
||||
include /etc/nginx/security-headers.conf;
|
||||
proxy_hide_header Content-Type;
|
||||
add_header Content-Type $fido_content_type;
|
||||
}
|
||||
|
||||
location /attachments {
|
||||
alias /etc/bitwarden/attachments/;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:5001/;
|
||||
}
|
||||
|
||||
location /icons/ {
|
||||
{{ if eq (getenv "BW_ICONS_PROXY_TO_CLOUD") "true" }}
|
||||
proxy_pass https://icons.bitwarden.net/;
|
||||
proxy_set_header Host icons.bitwarden.net;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_ssl_server_name on;
|
||||
{{ else }}
|
||||
proxy_pass http://localhost:5004/;
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
location /notifications/ {
|
||||
proxy_pass http://localhost:5006/;
|
||||
}
|
||||
|
||||
location /notifications/hub {
|
||||
proxy_pass http://localhost:5006/hub;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
}
|
||||
|
||||
location /events/ {
|
||||
proxy_pass http://localhost:5003/;
|
||||
}
|
||||
|
||||
location /sso {
|
||||
proxy_pass http://localhost:5007;
|
||||
{{ if eq (getenv "BW_ENABLE_SSL") "true" }}
|
||||
include /etc/nginx/security-headers-ssl.conf;
|
||||
{{ end }}
|
||||
include /etc/nginx/security-headers.conf;
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
}
|
||||
|
||||
location /identity {
|
||||
proxy_pass http://localhost:5005;
|
||||
{{ if eq (getenv "BW_ENABLE_SSL") "true" }}
|
||||
include /etc/nginx/security-headers-ssl.conf;
|
||||
{{ end }}
|
||||
include /etc/nginx/security-headers.conf;
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
}
|
||||
|
||||
location /admin {
|
||||
proxy_pass http://localhost:5000;
|
||||
{{ if eq (getenv "BW_ENABLE_SSL") "true" }}
|
||||
include /etc/nginx/security-headers-ssl.conf;
|
||||
{{ end }}
|
||||
include /etc/nginx/security-headers.conf;
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
}
|
||||
|
||||
{{ if eq (getenv "BW_ENABLE_KEY_CONNECTOR") "true" }}
|
||||
location /key-connector/ {
|
||||
proxy_pass {{ getenv "BW_KEY_CONNECTOR_INTERNAL_URL"}}/;
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
location /scim/ {
|
||||
proxy_pass http://localhost:5002/;
|
||||
}
|
||||
}
|
17
docker-unified/confd/nginx-config.toml
Normal file
17
docker-unified/confd/nginx-config.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[template]
|
||||
src = "nginx-config.conf.tmpl"
|
||||
dest = "/etc/nginx/http.d/bitwarden.conf"
|
||||
keys = [
|
||||
"BW_ENABLE_SSL_CA",
|
||||
"BW_SSL_CA_CERT",
|
||||
"BW_CSP",
|
||||
"BW_ENABLE_KEY_CONNECTOR",
|
||||
"BW_KEY_CONNECTOR_INTERNAL_URL",
|
||||
"BW_REAL_IPS",
|
||||
"BW_ENABLE_SSL",
|
||||
"BW_SSL_CERT",
|
||||
"BW_SSL_CIPHERS",
|
||||
"BW_SSL_KEY",
|
||||
"BW_SSL_PROTOCOLS",
|
||||
"BW_ICONS_PROXY_TO_CLOUD"
|
||||
]
|
56
docker-unified/docker-compose.yml
Normal file
56
docker-unified/docker-compose.yml
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
bitwarden:
|
||||
depends_on:
|
||||
- db
|
||||
env_file:
|
||||
- settings.env
|
||||
image: ${REGISTRY:-bitwarden}/self-host:${TAG:-latest}
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- bitwarden:/etc/bitwarden
|
||||
- logs:/var/log/bitwarden
|
||||
|
||||
# MariaDB Example
|
||||
db:
|
||||
environment:
|
||||
MARIADB_USER: "bitwarden"
|
||||
MARIADB_PASSWORD: "super_strong_password"
|
||||
MARIADB_DATABASE: "bitwarden_vault"
|
||||
MARIADB_RANDOM_ROOT_PASSWORD: "true"
|
||||
image: mariadb:10
|
||||
restart: always
|
||||
volumes:
|
||||
- data:/var/lib/mysql
|
||||
|
||||
# PostgreSQL Example
|
||||
# db:
|
||||
# environment:
|
||||
# POSTGRES_USER: "bitwarden"
|
||||
# POSTGRES_PASSWORD: "super_strong_password"
|
||||
# POSTGRES_DB: "bitwarden_vault"
|
||||
# image: postgres:15
|
||||
# restart: always
|
||||
# volumes:
|
||||
# - data:/var/lib/postgresql/data
|
||||
|
||||
# MS SQL Server Example
|
||||
# Docs: https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-docker-container-deployment
|
||||
# db:
|
||||
# environment:
|
||||
# MSSQL_SA_PASSWORD: "super_strong_password"
|
||||
# ACCEPT_EULA: Y
|
||||
# image: mcr.microsoft.com/mssql/server:2019-latest
|
||||
# restart: always
|
||||
# volumes:
|
||||
# - data:/var/opt/mssql/data
|
||||
|
||||
volumes:
|
||||
bitwarden:
|
||||
logs:
|
||||
data:
|
81
docker-unified/entrypoint.sh
Normal file
81
docker-unified/entrypoint.sh
Normal file
@ -0,0 +1,81 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Translate environment variables for application settings
|
||||
VAULT_SERVICE_URI=https://$BW_DOMAIN
|
||||
MYSQL_CONNECTION_STRING="server=$BW_DB_SERVER;database=$BW_DB_DATABASE;user=$BW_DB_USERNAME;password=$BW_DB_PASSWORD"
|
||||
POSTGRESQL_CONNECTION_STRING="Host=$BW_DB_SERVER;Database=$BW_DB_DATABASE;Username=$BW_DB_USERNAME;Password=$BW_DB_PASSWORD"
|
||||
SQLSERVER_CONNECTION_STRING="Server=$BW_DB_SERVER;Database=$BW_DB_DATABASE;User Id=$BW_DB_USERNAME;Password=$BW_DB_PASSWORD;"
|
||||
INTERNAL_IDENTITY_KEY=$(openssl rand -hex 30)
|
||||
OIDC_IDENTITY_CLIENT_KEY=$(openssl rand -hex 30)
|
||||
DUO_AKEY=$(openssl rand -hex 30)
|
||||
|
||||
export globalSettings__baseServiceUri__vault=${globalSettings__baseServiceUri__vault:-$VAULT_SERVICE_URI}
|
||||
export globalSettings__installation__id=$BW_INSTALLATION_ID
|
||||
export globalSettings__installation__key=$BW_INSTALLATION_KEY
|
||||
export globalSettings__internalIdentityKey=${globalSettings__internalIdentityKey:-$INTERNAL_IDENTITY_KEY}
|
||||
export globalSettings__oidcIdentityClientKey=${globalSettings__oidcIdentityClientKey:-$OIDC_IDENTITY_CLIENT_KEY}
|
||||
export globalSettings__duo__aKey=${globalSettings__duo__aKey:-$DUO_AKEY}
|
||||
|
||||
export globalSettings__databaseProvider=$BW_DB_PROVIDER
|
||||
export globalSettings__mysql__connectionString=${globalSettings__mysql__connectionString:-$MYSQL_CONNECTION_STRING}
|
||||
export globalSettings__postgreSql__connectionString=${globalSettings__postgreSql__connectionString:-$POSTGRESQL_CONNECTION_STRING}
|
||||
export globalSettings__sqlServer__connectionString=${globalSettings__sqlServer__connectionString:-$SQLSERVER_CONNECTION_STRING}
|
||||
|
||||
# Generate Identity certificate
|
||||
if [ ! -f /etc/bitwarden/identity.pfx ]; then
|
||||
openssl req \
|
||||
-x509 \
|
||||
-newkey rsa:4096 \
|
||||
-sha256 \
|
||||
-nodes \
|
||||
-keyout /etc/bitwarden/identity.key \
|
||||
-out /etc/bitwarden/identity.crt \
|
||||
-subj "/CN=Bitwarden IdentityServer" \
|
||||
-days 36500
|
||||
|
||||
openssl pkcs12 \
|
||||
-export \
|
||||
-out /etc/bitwarden/identity.pfx \
|
||||
-inkey /etc/bitwarden/identity.key \
|
||||
-in /etc/bitwarden/identity.crt \
|
||||
-passout pass:$globalSettings__identityServer__certificatePassword
|
||||
|
||||
rm /etc/bitwarden/identity.crt
|
||||
rm /etc/bitwarden/identity.key
|
||||
fi
|
||||
|
||||
cp /etc/bitwarden/identity.pfx /app/Identity/identity.pfx
|
||||
cp /etc/bitwarden/identity.pfx /app/Sso/identity.pfx
|
||||
|
||||
# Generate SSL certificates
|
||||
if [ "$BW_ENABLE_SSL" == "true" -a ! -f /etc/bitwarden/ssl.key ]; then
|
||||
openssl req \
|
||||
-x509 \
|
||||
-newkey rsa:4096 \
|
||||
-sha256 \
|
||||
-nodes \
|
||||
-days 36500 \
|
||||
-keyout /etc/bitwarden/${BW_SSL_KEY:-ssl.key} \
|
||||
-out /etc/bitwarden/${BW_SSL_CERT:-ssl.crt} \
|
||||
-reqexts SAN \
|
||||
-extensions SAN \
|
||||
-config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:${BW_DOMAIN:-localhost}\nbasicConstraints=CA:true")) \
|
||||
-subj "/C=US/ST=California/L=Santa Barbara/O=Bitwarden Inc./OU=Bitwarden/CN=${BW_DOMAIN:-localhost}"
|
||||
fi
|
||||
|
||||
# Launch a loop to rotate nginx logs on a daily basis
|
||||
/bin/sh -c "/logrotate.sh loop >/dev/null 2>&1 &"
|
||||
|
||||
/usr/local/bin/confd -onetime -backend env
|
||||
|
||||
# Enable/Disable services
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_ADMIN}/" /etc/supervisor.d/admin.ini
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_API}/" /etc/supervisor.d/api.ini
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_EVENTS}/" /etc/supervisor.d/events.ini
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_ICONS}/" /etc/supervisor.d/icons.ini
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_IDENTITY}/" /etc/supervisor.d/identity.ini
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_NOTIFICATIONS}/" /etc/supervisor.d/notifications.ini
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_SCIM}/" /etc/supervisor.d/scim.ini
|
||||
sed -i "s/autostart=true/autostart=${BW_ENABLE_SSO}/" /etc/supervisor.d/sso.ini
|
||||
|
||||
exec /usr/bin/supervisord
|
15
docker-unified/nginx/logrotate.sh
Normal file
15
docker-unified/nginx/logrotate.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
while true
|
||||
do
|
||||
[ "$1" = "loop" ] && sleep $((24 * 3600 - (`date +%_H` * 3600 + `date +%_M` * 60 + `date +%_S`)))
|
||||
ts=$(date +%Y%m%d_%H%M%S)
|
||||
mv /var/log/nginx/access.log /var/log/nginx/access.$ts.log
|
||||
mv /var/log/nginx/error.log /var/log/nginx/error.$ts.log
|
||||
kill -USR1 `cat /var/run/nginx/nginx.pid`
|
||||
sleep 1
|
||||
gzip /var/log/nginx/access.$ts.log
|
||||
gzip /var/log/nginx/error.$ts.log
|
||||
find /var/log/nginx/ -name "*.gz" -mtime +32 -delete
|
||||
[ "$1" != "loop" ] && break
|
||||
done
|
138
docker-unified/nginx/mime.types
Normal file
138
docker-unified/nginx/mime.types
Normal file
@ -0,0 +1,138 @@
|
||||
types {
|
||||
|
||||
# Data interchange
|
||||
|
||||
application/atom+xml atom;
|
||||
application/json json map topojson;
|
||||
application/ld+json jsonld;
|
||||
application/rss+xml rss;
|
||||
application/vnd.geo+json geojson;
|
||||
application/xml rdf xml;
|
||||
|
||||
|
||||
# JavaScript
|
||||
|
||||
# Normalize to standard type.
|
||||
# https://tools.ietf.org/html/rfc4329#section-7.2
|
||||
application/javascript js;
|
||||
|
||||
|
||||
# Manifest files
|
||||
|
||||
application/manifest+json webmanifest;
|
||||
application/x-web-app-manifest+json webapp;
|
||||
text/cache-manifest appcache;
|
||||
|
||||
|
||||
# Media files
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mp4 aac f4a f4b m4a;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg oga ogg opus;
|
||||
audio/x-realaudio ra;
|
||||
audio/x-wav wav;
|
||||
image/bmp bmp;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
image/jxr jxr hdp wdp;
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-jng jng;
|
||||
video/3gpp 3gp 3gpp;
|
||||
video/mp4 f4p f4v m4v mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/ogg ogv;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asf asx;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
|
||||
# Serving `.ico` image files with a different media type
|
||||
# prevents Internet Explorer from displaying then as images:
|
||||
# https://github.com/h5bp/html5-boilerplate/commit/37b5fec090d00f38de64b591bcddcb205aadf8ee
|
||||
|
||||
image/x-icon cur ico;
|
||||
|
||||
|
||||
# Microsoft Office
|
||||
|
||||
application/msword doc;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
|
||||
|
||||
|
||||
# Web fonts
|
||||
|
||||
application/font-woff woff;
|
||||
application/font-woff2 woff2;
|
||||
application/vnd.ms-fontobject eot;
|
||||
|
||||
# Browsers usually ignore the font media types and simply sniff
|
||||
# the bytes to figure out the font type.
|
||||
# https://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern
|
||||
#
|
||||
# However, Blink and WebKit based browsers will show a warning
|
||||
# in the console if the following font types are served with any
|
||||
# other media types.
|
||||
|
||||
application/x-font-ttf ttc ttf;
|
||||
font/opentype otf;
|
||||
|
||||
|
||||
# Other
|
||||
|
||||
application/java-archive ear jar war;
|
||||
application/mac-binhex40 hqx;
|
||||
application/octet-stream bin deb dll dmg exe img iso msi msm msp safariextz;
|
||||
application/pdf pdf;
|
||||
application/postscript ai eps ps;
|
||||
application/rtf rtf;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-bb-appworld bbaw;
|
||||
application/x-bittorrent torrent;
|
||||
application/x-chrome-extension crx;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-opera-extension oex;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot pdb prc;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert crt der pem;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xslt+xml xsl;
|
||||
application/zip zip;
|
||||
text/css css;
|
||||
text/csv csv;
|
||||
text/html htm html shtml;
|
||||
text/markdown md;
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vcard vcard vcf;
|
||||
text/vnd.rim.location.xloc xloc;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/vtt vtt;
|
||||
text/x-component htc;
|
||||
|
||||
}
|
147
docker-unified/nginx/nginx.conf
Normal file
147
docker-unified/nginx/nginx.conf
Normal file
@ -0,0 +1,147 @@
|
||||
# nginx Configuration File
|
||||
# http://wiki.nginx.org/Configuration
|
||||
|
||||
daemon off;
|
||||
|
||||
# Run as a less privileged user for security reasons.
|
||||
# user www www;
|
||||
|
||||
# How many worker threads to run;
|
||||
# "auto" sets it to the number of CPU cores available in the system, and
|
||||
# offers the best performance. Don't set it higher than the number of CPU
|
||||
# cores if changing this parameter.
|
||||
|
||||
# The maximum number of connections for Nginx is calculated by:
|
||||
# max_clients = worker_processes * worker_connections
|
||||
worker_processes auto;
|
||||
|
||||
# Maximum open file descriptors per process;
|
||||
# should be > worker_connections.
|
||||
worker_rlimit_nofile 8192;
|
||||
|
||||
events {
|
||||
# When you need > 8000 * cpu_cores connections, you start optimizing your OS,
|
||||
# and this is probably the point at which you hire people who are smarter than
|
||||
# you, as this is *a lot* of requests.
|
||||
worker_connections 8000;
|
||||
}
|
||||
|
||||
# Default error log file
|
||||
# (this is only used when you don't override error_log on a server{} level)
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx/nginx.pid;
|
||||
|
||||
http {
|
||||
# Include proxy and server configuration.
|
||||
include /etc/nginx/proxy.conf;
|
||||
include /etc/nginx/http.d/bitwarden.conf;
|
||||
|
||||
# Hide nginx version information.
|
||||
server_tokens off;
|
||||
|
||||
# Define the MIME types for files.
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Update charset_types to match updated mime.types.
|
||||
# text/html is always included by charset module.
|
||||
# Default: text/html text/xml text/plain text/vnd.wap.wml application/javascript application/rss+xml
|
||||
charset_types
|
||||
text/css
|
||||
text/plain
|
||||
text/vnd.wap.wml
|
||||
application/javascript
|
||||
application/json
|
||||
application/rss+xml
|
||||
application/xml;
|
||||
|
||||
# Format to use in log files
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
# Default log file
|
||||
# (this is only used when you don't override access_log on a server{} level)
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# How long to allow each connection to stay idle; longer values are better
|
||||
# for each individual client, particularly for SSL, but means that worker
|
||||
# connections are tied up longer. (Default: 65)
|
||||
keepalive_timeout 20;
|
||||
|
||||
# Speed up file transfers by using sendfile() to copy directly
|
||||
# between descriptors rather than using read()/write().
|
||||
# For performance reasons, on FreeBSD systems w/ ZFS
|
||||
# this option should be disabled as ZFS's ARC caches
|
||||
# frequently used files in RAM by default.
|
||||
sendfile on;
|
||||
|
||||
# Tell Nginx not to send out partial frames; this increases throughput
|
||||
# since TCP frames are filled up before being sent out. (adds TCP_CORK)
|
||||
tcp_nopush on;
|
||||
|
||||
|
||||
# Compression
|
||||
|
||||
# Enable Gzip compressed.
|
||||
gzip on;
|
||||
|
||||
# Compression level (1-9).
|
||||
# 5 is a perfect compromise between size and cpu usage, offering about
|
||||
# 75% reduction for most ascii files (almost identical to level 9).
|
||||
gzip_comp_level 5;
|
||||
|
||||
# Don't compress anything that's already small and unlikely to shrink much
|
||||
# if at all (the default is 20 bytes, which is bad as that usually leads to
|
||||
# larger files after gzipping).
|
||||
gzip_min_length 256;
|
||||
|
||||
# Compress data even for clients that are connecting to us via proxies,
|
||||
# identified by the "Via" header (required for CloudFront).
|
||||
gzip_proxied any;
|
||||
|
||||
# Tell proxies to cache both the gzipped and regular version of a resource
|
||||
# whenever the client's Accept-Encoding capabilities header varies;
|
||||
# Avoids the issue where a non-gzip capable client (which is extremely rare
|
||||
# today) would display gibberish if their proxy gave them the gzipped version.
|
||||
gzip_vary on;
|
||||
|
||||
# Compress all output labeled with one of the following MIME-types.
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/manifest+json
|
||||
application/rss+xml
|
||||
application/vnd.geo+json
|
||||
application/vnd.ms-fontobject
|
||||
application/x-font-ttf
|
||||
application/x-web-app-manifest+json
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/opentype
|
||||
image/bmp
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
text/cache-manifest
|
||||
text/css
|
||||
text/plain
|
||||
text/vcard
|
||||
text/vnd.rim.location.xloc
|
||||
text/vtt
|
||||
text/x-component
|
||||
text/x-cross-domain-policy;
|
||||
# text/html is always compressed by HttpGzipModule
|
||||
|
||||
# This should be turned on if you are going to have pre-compressed copies (.gz) of
|
||||
# static files available. If not it should be left off as it will cause extra I/O
|
||||
# for the check. It is best if you enable this in a location{} block for
|
||||
# a specific directory, or on an individual server{} level.
|
||||
# gzip_static on;
|
||||
|
||||
# Content type for FIDO U2F facets
|
||||
map $uri $fido_content_type {
|
||||
default "application/fido.trusted-apps+json";
|
||||
}
|
||||
}
|
15
docker-unified/nginx/proxy.conf
Normal file
15
docker-unified/nginx/proxy.conf
Normal file
@ -0,0 +1,15 @@
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Url-Scheme $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
client_max_body_size 505m;
|
||||
client_body_buffer_size 128k;
|
||||
proxy_connect_timeout 90;
|
||||
proxy_send_timeout 90;
|
||||
proxy_read_timeout 90;
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
proxy_busy_buffers_size 256k;
|
||||
large_client_header_buffers 4 32k;
|
2
docker-unified/nginx/security-headers-ssl.conf
Normal file
2
docker-unified/nginx/security-headers-ssl.conf
Normal file
@ -0,0 +1,2 @@
|
||||
# This will enforce HTTP browsing into HTTPS and avoid ssl stripping attack. 6 months age
|
||||
add_header Strict-Transport-Security max-age=15768000;
|
3
docker-unified/nginx/security-headers.conf
Normal file
3
docker-unified/nginx/security-headers.conf
Normal file
@ -0,0 +1,3 @@
|
||||
add_header Referrer-Policy same-origin;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
61
docker-unified/settings.env
Normal file
61
docker-unified/settings.env
Normal file
@ -0,0 +1,61 @@
|
||||
#####################
|
||||
# Required Settings #
|
||||
#####################
|
||||
|
||||
# Server hostname
|
||||
BW_DOMAIN=bitwarden.yourdomain.com
|
||||
|
||||
# Database
|
||||
# Available providers are sqlserver, postgresql, or mysql/mariadb
|
||||
BW_DB_PROVIDER=mysql
|
||||
BW_DB_SERVER=db
|
||||
BW_DB_DATABASE=bitwarden_vault
|
||||
BW_DB_USERNAME=bitwarden
|
||||
BW_DB_PASSWORD=super_strong_password
|
||||
|
||||
# Installation information
|
||||
# Get your ID and key from https://bitwarden.com/host/
|
||||
BW_INSTALLATION_ID=00000000-0000-0000-0000-000000000000
|
||||
BW_INSTALLATION_KEY=xxxxxxxxxxxx
|
||||
|
||||
#####################
|
||||
# Optional Settings #
|
||||
#####################
|
||||
# Learn more here: https://bitwarden.com/help/environment-variables/
|
||||
|
||||
# SSL
|
||||
#BW_ENABLE_SSL=true
|
||||
#BW_ENABLE_SSL_CA=true
|
||||
#BW_SSL_CERT=ssl.crt
|
||||
#BW_SSL_KEY=ssl.key
|
||||
#BW_SSL_CA_CERT=ca.crt
|
||||
|
||||
# Services
|
||||
# Some services, namely for enterprise use cases, are disabled by default. Defaults shown below.
|
||||
#BW_ENABLE_ADMIN=true
|
||||
#BW_ENABLE_API=true
|
||||
#BW_ENABLE_EVENTS=false
|
||||
#BW_ENABLE_ICONS=true
|
||||
#BW_ENABLE_IDENTITY=true
|
||||
#BW_ENABLE_NOTIFICATIONS=true
|
||||
#BW_ENABLE_SCIM=false
|
||||
#BW_ENABLE_SSO=false
|
||||
|
||||
#BW_ICONS_PROXY_TO_CLOUD=false
|
||||
|
||||
# Mail
|
||||
#globalSettings__mail__replyToEmail=noreply@$BW_DOMAIN
|
||||
#globalSettings__mail__smtp__host=smtphost.example.com
|
||||
#globalSettings__mail__smtp__port=587
|
||||
#globalSettings__mail__smtp__ssl=false
|
||||
#globalSettings__mail__smtp__username=smtpusername
|
||||
#globalSettings__mail__smtp__password=smtppassword
|
||||
|
||||
# Yubikey
|
||||
#globalSettings__yubico__clientId=REPLACE
|
||||
#globalSettings__yubico__key=REPLACE
|
||||
|
||||
# Other
|
||||
#globalSettings__disableUserRegistration=false
|
||||
#globalSettings__hibpApiKey=REPLACE
|
||||
#adminSettings__admins="admin1@email.com,admin2@email.com"
|
9
docker-unified/supervisord/admin.ini
Normal file
9
docker-unified/supervisord/admin.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[program:admin]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Admin.dll"
|
||||
directory=/app/Admin
|
||||
environment=ASPNETCORE_URLS="http://+:5000"
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/admin.log
|
9
docker-unified/supervisord/api.ini
Normal file
9
docker-unified/supervisord/api.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[program:api]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Api.dll"
|
||||
directory=/app/Api
|
||||
environment=ASPNETCORE_URLS="http://+:5001"
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/api.log
|
9
docker-unified/supervisord/events.ini
Normal file
9
docker-unified/supervisord/events.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[program:events]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Events.dll"
|
||||
directory=/app/Events
|
||||
environment=ASPNETCORE_URLS="http://+:5003"
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/events.log
|
9
docker-unified/supervisord/icons.ini
Normal file
9
docker-unified/supervisord/icons.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[program:icons]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Icons.dll"
|
||||
directory=/app/Icons
|
||||
environment=ASPNETCORE_URLS="http://+:5004"
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/icons.log
|
10
docker-unified/supervisord/identity.ini
Normal file
10
docker-unified/supervisord/identity.ini
Normal file
@ -0,0 +1,10 @@
|
||||
[program:identity]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Identity.dll"
|
||||
directory=/app/Identity
|
||||
environment=ASPNETCORE_URLS="http://+:5005"
|
||||
priority=1
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/identity.log
|
7
docker-unified/supervisord/nginx.ini
Normal file
7
docker-unified/supervisord/nginx.ini
Normal file
@ -0,0 +1,7 @@
|
||||
[program:nginx]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=nginx
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/nginx.log
|
9
docker-unified/supervisord/notifications.ini
Normal file
9
docker-unified/supervisord/notifications.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[program:notifications]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Notifications.dll"
|
||||
directory=/app/Notifications
|
||||
environment=ASPNETCORE_URLS="http://+:5006"
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/notifications.log
|
9
docker-unified/supervisord/scim.ini
Normal file
9
docker-unified/supervisord/scim.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[program:scim]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Scim.dll"
|
||||
directory=/app/Scim
|
||||
environment=ASPNETCORE_URLS="http://+:5002"
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/scim.log
|
9
docker-unified/supervisord/sso.ini
Normal file
9
docker-unified/supervisord/sso.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[program:sso]
|
||||
autostart=true
|
||||
autorestart=true
|
||||
command=/usr/bin/dotnet "Sso.dll"
|
||||
directory=/app/Sso
|
||||
environment=ASPNETCORE_URLS="http://+:5007"
|
||||
redirect_stderr=true
|
||||
startsecs=15
|
||||
stdout_logfile=/var/log/bitwarden/sso.log
|
15
docker-unified/supervisord/supervisord.conf
Normal file
15
docker-unified/supervisord/supervisord.conf
Normal file
@ -0,0 +1,15 @@
|
||||
[unix_http_server]
|
||||
file=/run/supervisord.sock ; the path to the socket file
|
||||
|
||||
[supervisord]
|
||||
logfile=/var/log/supervisord.log ; main log file; default $CWD/supervisord.log
|
||||
nodaemon=true ; start in foreground if true; default false
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///run/supervisord.sock ; use a unix:// URL for a unix socket
|
||||
|
||||
[include]
|
||||
files = /etc/supervisor.d/*.ini
|
@ -22,27 +22,26 @@ build() {
|
||||
PROJECT=$1; shift
|
||||
|
||||
case "$PROJECT" in
|
||||
"api" | "Api") build Api $PWD/src/Api ;;
|
||||
"admin" | "Admin") build Admin $PWD/src/Admin ;;
|
||||
"identity" | "Identity") build Identity $PWD/src/Identity ;;
|
||||
"events" | "Events") build Events $PWD/src/Events ;;
|
||||
"api" | "Api") build Api $PWD/src/Api ;;
|
||||
"billing" | "Billing") build Billing $PWD/src/Billing ;;
|
||||
"sso" | "Sso") build Sso $PWD/bitwarden_license/src/Sso ;;
|
||||
"server" | "Server") build Server $PWD/util/Server ;;
|
||||
"icons" | "Icons") build Icons $PWD/src/Icons ;;
|
||||
"notifications" | "Notifications") build Notifications $PWD/src/Notifications ;;
|
||||
"setup" | "Setup") build Setup $PWD/util/Setup ;;
|
||||
"events" | "Events") build Events $PWD/src/Events ;;
|
||||
"eventsprocessor" | "EventsProcessor") build EventsProcessor $PWD/src/EventsProcessor ;;
|
||||
"icons" | "Icons") build Icons $PWD/src/Icons ;;
|
||||
"identity" | "Identity") build Identity $PWD/src/Identity ;;
|
||||
"notifications" | "Notifications") build Notifications $PWD/src/Notifications ;;
|
||||
"server" | "Server") build Server $PWD/util/Server ;;
|
||||
"sso" | "Sso") build Sso $PWD/bitwarden_license/src/Sso ;;
|
||||
"")
|
||||
build Api $PWD/src/Api
|
||||
build Admin $PWD/src/Admin
|
||||
build Identity $PWD/src/Identity
|
||||
build Events $PWD/src/Events
|
||||
build Billing $PWD/src/Billing
|
||||
build Sso $PWD/bitwarden_license/src/Sso
|
||||
build Server $PWD/util/Server
|
||||
build Icons $PWD/src/Icons
|
||||
build Notifications $PWD/src/Notifications
|
||||
build Admin $PWD/src/Admin
|
||||
build Api $PWD/src/Api
|
||||
build Billing $PWD/src/Billing
|
||||
build Events $PWD/src/Events
|
||||
build EventsProcessor $PWD/src/EventsProcessor
|
||||
build Icons $PWD/src/Icons
|
||||
build Identity $PWD/src/Identity
|
||||
build Notifications $PWD/src/Notifications
|
||||
build Server $PWD/util/Server
|
||||
build Sso $PWD/bitwarden_license/src/Sso
|
||||
;;
|
||||
esac
|
||||
|
@ -22,10 +22,6 @@ docker_build() {
|
||||
|
||||
echo "Building docker image: bitwarden/$project_name_lower:$docker_tag"
|
||||
echo "=============================="
|
||||
if [ "$project_name_lower" == "k8s-proxy" ]; then
|
||||
docker build -f $project_dir/Dockerfile-k8s -t bitwarden/$project_name_lower:$docker_tag $project_dir
|
||||
fi
|
||||
|
||||
docker build -t bitwarden/$project_name_lower:$docker_tag $project_dir
|
||||
|
||||
if [ "$docker_push" == "1" ]; then
|
||||
@ -59,35 +55,34 @@ done
|
||||
|
||||
|
||||
case "$PROJECT" in
|
||||
"api" | "Api") docker_build Api $PWD/src/Api $TAG $PUSH ;;
|
||||
"admin" | "Admin") docker_build Admin $PWD/src/Admin $TAG $PUSH ;;
|
||||
"identity" | "Identity") docker_build Identity $PWD/src/Identity $TAG $PUSH ;;
|
||||
"events" | "Events") docker_build Events $PWD/src/Events $TAG $PUSH ;;
|
||||
#"billing" | "Billing") docker_build Billing $PWD/src/Billing $TAG $PUSH ;;
|
||||
"sso" | "Sso") docker_build Sso $PWD/bitwarden_license/src/Sso $TAG $PUSH ;;
|
||||
"server" | "Server") docker_build Server $PWD/util/Server $TAG $PUSH ;;
|
||||
"nginx" | "Nginx") docker_build Nginx $PWD/util/Nginx $TAG $PUSH ;;
|
||||
"k8s-proxy" | "K8s-Proxy") docker_build K8s-Proxy $PWD/util/Nginx $TAG $PUSH ;;
|
||||
"api" | "Api") docker_build Api $PWD/src/Api $TAG $PUSH ;;
|
||||
"attachments" | "Attachments") docker_build Attachments $PWD/util/Attachments $TAG $PUSH ;;
|
||||
"icons" | "Icons") docker_build Icons $PWD/src/Icons $TAG $PUSH ;;
|
||||
"notifications" | "Notifications") docker_build Notifications $PWD/src/Notifications $TAG $PUSH ;;
|
||||
"mssql" | "MsSql" | "Mssql") docker_build MsSql $PWD/util/MsSql $TAG $PUSH ;;
|
||||
"setup" | "Setup") docker_build Setup $PWD/util/Setup $TAG $PUSH ;;
|
||||
#"billing" | "Billing") docker_build Billing $PWD/src/Billing $TAG $PUSH ;;
|
||||
"events" | "Events") docker_build Events $PWD/src/Events $TAG $PUSH ;;
|
||||
"eventsprocessor" | "EventsProcessor") docker_build EventsProcessor $PWD/src/EventsProcessor $TAG $PUSH ;;
|
||||
"icons" | "Icons") docker_build Icons $PWD/src/Icons $TAG $PUSH ;;
|
||||
"identity" | "Identity") docker_build Identity $PWD/src/Identity $TAG $PUSH ;;
|
||||
"mssql" | "MsSql" | "Mssql") docker_build MsSql $PWD/util/MsSql $TAG $PUSH ;;
|
||||
"nginx" | "Nginx") docker_build Nginx $PWD/util/Nginx $TAG $PUSH ;;
|
||||
"notifications" | "Notifications") docker_build Notifications $PWD/src/Notifications $TAG $PUSH ;;
|
||||
"server" | "Server") docker_build Server $PWD/util/Server $TAG $PUSH ;;
|
||||
"setup" | "Setup") docker_build Setup $PWD/util/Setup $TAG $PUSH ;;
|
||||
"sso" | "Sso") docker_build Sso $PWD/bitwarden_license/src/Sso $TAG $PUSH ;;
|
||||
"")
|
||||
docker_build Api $PWD/src/Api $TAG $PUSH
|
||||
docker_build Admin $PWD/src/Admin $TAG $PUSH
|
||||
docker_build Identity $PWD/src/Identity $TAG $PUSH
|
||||
docker_build Events $PWD/src/Events $TAG $PUSH
|
||||
#docker_build Billing $PWD/src/Billing $TAG $PUSH
|
||||
docker_build Sso $PWD/bitwarden_license/src/Sso $TAG $PUSH
|
||||
docker_build Server $PWD/util/Server $TAG $PUSH
|
||||
docker_build Nginx $PWD/util/Nginx $TAG $PUSH
|
||||
docker_build Api $PWD/src/Api $TAG $PUSH
|
||||
docker_build Attachments $PWD/util/Attachments $TAG $PUSH
|
||||
docker_build Icons $PWD/src/Icons $TAG $PUSH
|
||||
docker_build Notifications $PWD/src/Notifications $TAG $PUSH
|
||||
docker_build MsSql $PWD/util/MsSql $TAG $PUSH
|
||||
docker_build Setup $PWD/util/Setup $TAG $PUSH
|
||||
#docker_build Billing $PWD/src/Billing $TAG $PUSH
|
||||
docker_build Events $PWD/src/Events $TAG $PUSH
|
||||
docker_build EventsProcessor $PWD/src/EventsProcessor $TAG $PUSH
|
||||
docker_build Icons $PWD/src/Icons $TAG $PUSH
|
||||
docker_build Identity $PWD/src/Identity $TAG $PUSH
|
||||
docker_build MsSql $PWD/util/MsSql $TAG $PUSH
|
||||
docker_build Nginx $PWD/util/Nginx $TAG $PUSH
|
||||
docker_build Notifications $PWD/src/Notifications $TAG $PUSH
|
||||
docker_build Server $PWD/util/Server $TAG $PUSH
|
||||
docker_build Setup $PWD/util/Setup $TAG $PUSH
|
||||
docker_build Sso $PWD/bitwarden_license/src/Sso $TAG $PUSH
|
||||
;;
|
||||
esac
|
||||
|
@ -5,6 +5,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\util\MySqlMigrations\MySqlMigrations.csproj" />
|
||||
<ProjectReference Include="..\..\util\PostgresMigrations\PostgresMigrations.csproj" />
|
||||
<ProjectReference Include="..\SharedWeb\SharedWeb.csproj" />
|
||||
<ProjectReference Include="..\..\util\Migrator\Migrator.csproj" />
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
|
@ -1,25 +1,19 @@
|
||||
using System.Data.SqlClient;
|
||||
using Bit.Core.Jobs;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Migrator;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Admin.HostedServices;
|
||||
|
||||
public class DatabaseMigrationHostedService : IHostedService, IDisposable
|
||||
{
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<DatabaseMigrationHostedService> _logger;
|
||||
private readonly DbMigrator _dbMigrator;
|
||||
private readonly IDbMigrator _dbMigrator;
|
||||
|
||||
public DatabaseMigrationHostedService(
|
||||
GlobalSettings globalSettings,
|
||||
ILogger<DatabaseMigrationHostedService> logger,
|
||||
ILogger<DbMigrator> migratorLogger,
|
||||
ILogger<JobListener> listenerLogger)
|
||||
IDbMigrator dbMigrator,
|
||||
ILogger<DatabaseMigrationHostedService> logger)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_logger = logger;
|
||||
_dbMigrator = new DbMigrator(globalSettings.SqlServer.ConnectionString, migratorLogger);
|
||||
_dbMigrator = dbMigrator;
|
||||
}
|
||||
|
||||
public virtual async Task StartAsync(CancellationToken cancellationToken)
|
||||
@ -32,7 +26,7 @@ public class DatabaseMigrationHostedService : IHostedService, IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
_dbMigrator.MigrateMsSqlDatabase(true, cancellationToken);
|
||||
_dbMigrator.MigrateDatabase(true, cancellationToken);
|
||||
// TODO: Maybe flip a flag somewhere to indicate migration is complete??
|
||||
break;
|
||||
}
|
||||
|
@ -42,7 +42,21 @@ public class Startup
|
||||
StripeConfiguration.MaxNetworkRetries = globalSettings.Stripe.MaxNetworkRetries;
|
||||
|
||||
// Repositories
|
||||
services.AddSqlServerRepositories(globalSettings);
|
||||
var databaseProvider = services.AddDatabaseRepositories(globalSettings);
|
||||
switch (databaseProvider)
|
||||
{
|
||||
case Core.Enums.SupportedDatabaseProviders.SqlServer:
|
||||
services.AddSingleton<IDbMigrator, Migrator.SqlServerDbMigrator>();
|
||||
break;
|
||||
case Core.Enums.SupportedDatabaseProviders.MySql:
|
||||
services.AddSingleton<IDbMigrator, MySqlMigrations.MySqlDbMigrator>();
|
||||
break;
|
||||
case Core.Enums.SupportedDatabaseProviders.Postgres:
|
||||
services.AddSingleton<IDbMigrator, PostgresMigrations.PostgresDbMigrator>();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Context
|
||||
services.AddScoped<ICurrentContext, CurrentContext>();
|
||||
|
@ -3211,82 +3211,96 @@
|
||||
"commercial.core": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2022.8.4"
|
||||
"Core": "[2022.10.0, )"
|
||||
}
|
||||
},
|
||||
"core": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AWSSDK.SQS": "3.7.2.47",
|
||||
"AWSSDK.SimpleEmail": "3.7.0.150",
|
||||
"AspNetCoreRateLimit": "4.0.2",
|
||||
"AspNetCoreRateLimit.Redis": "1.0.1",
|
||||
"Azure.Extensions.AspNetCore.DataProtection.Blobs": "1.2.1",
|
||||
"Azure.Storage.Blobs": "12.11.0",
|
||||
"Azure.Storage.Queues": "12.9.0",
|
||||
"BitPay.Light": "1.0.1907",
|
||||
"Braintree": "5.12.0",
|
||||
"Fido2.AspNet": "3.0.0-beta2",
|
||||
"Handlebars.Net": "2.1.2",
|
||||
"IdentityServer4": "4.1.2",
|
||||
"IdentityServer4.AccessTokenValidation": "3.0.1",
|
||||
"MailKit": "3.2.0",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "6.0.4",
|
||||
"Microsoft.Azure.Cosmos.Table": "1.0.8",
|
||||
"Microsoft.Azure.NotificationHubs": "4.1.0",
|
||||
"Microsoft.Azure.ServiceBus": "5.2.0",
|
||||
"Microsoft.Data.SqlClient": "4.1.0",
|
||||
"Microsoft.Extensions.Caching.StackExchangeRedis": "6.0.6",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "6.0.1",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "6.0.1",
|
||||
"Microsoft.Extensions.Identity.Stores": "6.0.4",
|
||||
"Newtonsoft.Json": "13.0.1",
|
||||
"Otp.NET": "1.2.2",
|
||||
"Quartz": "3.4.0",
|
||||
"SendGrid": "9.27.0",
|
||||
"Sentry.Serilog": "3.16.0",
|
||||
"Serilog.AspNetCore": "5.0.0",
|
||||
"Serilog.Extensions.Logging": "3.1.0",
|
||||
"Serilog.Extensions.Logging.File": "2.0.0",
|
||||
"Serilog.Sinks.AzureCosmosDB": "2.0.0",
|
||||
"Serilog.Sinks.SyslogMessages": "2.0.6",
|
||||
"Stripe.net": "40.0.0",
|
||||
"YubicoDotNetClient": "1.2.0"
|
||||
"AWSSDK.SQS": "[3.7.2.47, )",
|
||||
"AWSSDK.SimpleEmail": "[3.7.0.150, )",
|
||||
"AspNetCoreRateLimit": "[4.0.2, )",
|
||||
"AspNetCoreRateLimit.Redis": "[1.0.1, )",
|
||||
"Azure.Extensions.AspNetCore.DataProtection.Blobs": "[1.2.1, )",
|
||||
"Azure.Storage.Blobs": "[12.11.0, )",
|
||||
"Azure.Storage.Queues": "[12.9.0, )",
|
||||
"BitPay.Light": "[1.0.1907, )",
|
||||
"Braintree": "[5.12.0, )",
|
||||
"Fido2.AspNet": "[3.0.0-beta2, )",
|
||||
"Handlebars.Net": "[2.1.2, )",
|
||||
"IdentityServer4": "[4.1.2, )",
|
||||
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
|
||||
"MailKit": "[3.2.0, )",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
|
||||
"Microsoft.Azure.Cosmos.Table": "[1.0.8, )",
|
||||
"Microsoft.Azure.NotificationHubs": "[4.1.0, )",
|
||||
"Microsoft.Azure.ServiceBus": "[5.2.0, )",
|
||||
"Microsoft.Data.SqlClient": "[4.1.0, )",
|
||||
"Microsoft.Extensions.Caching.StackExchangeRedis": "[6.0.6, )",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "[6.0.1, )",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "[6.0.1, )",
|
||||
"Microsoft.Extensions.Identity.Stores": "[6.0.4, )",
|
||||
"Newtonsoft.Json": "[13.0.1, )",
|
||||
"Otp.NET": "[1.2.2, )",
|
||||
"Quartz": "[3.4.0, )",
|
||||
"SendGrid": "[9.27.0, )",
|
||||
"Sentry.Serilog": "[3.16.0, )",
|
||||
"Serilog.AspNetCore": "[5.0.0, )",
|
||||
"Serilog.Extensions.Logging": "[3.1.0, )",
|
||||
"Serilog.Extensions.Logging.File": "[2.0.0, )",
|
||||
"Serilog.Sinks.AzureCosmosDB": "[2.0.0, )",
|
||||
"Serilog.Sinks.SyslogMessages": "[2.0.6, )",
|
||||
"Stripe.net": "[40.0.0, )",
|
||||
"YubicoDotNetClient": "[1.2.0, )"
|
||||
}
|
||||
},
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2022.8.4",
|
||||
"Dapper": "2.0.123",
|
||||
"System.Data.SqlClient": "4.8.3"
|
||||
"Core": "[2022.10.0, )",
|
||||
"Dapper": "[2.0.123, )",
|
||||
"System.Data.SqlClient": "[4.8.3, )"
|
||||
}
|
||||
},
|
||||
"infrastructure.entityframework": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "11.0.0",
|
||||
"Core": "2022.8.4",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.4",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "6.0.4",
|
||||
"Pomelo.EntityFrameworkCore.MySql": "6.0.1",
|
||||
"linq2db.EntityFrameworkCore": "6.7.1"
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[11.0.0, )",
|
||||
"Core": "[2022.10.0, )",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[6.0.4, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "[6.0.4, )",
|
||||
"Pomelo.EntityFrameworkCore.MySql": "[6.0.1, )",
|
||||
"linq2db.EntityFrameworkCore": "[6.7.1, )"
|
||||
}
|
||||
},
|
||||
"migrator": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2022.8.4",
|
||||
"Microsoft.Extensions.Logging": "6.0.0",
|
||||
"dbup-sqlserver": "4.5.0"
|
||||
"Core": "[2022.10.0, )",
|
||||
"Microsoft.Extensions.Logging": "[6.0.0, )",
|
||||
"dbup-sqlserver": "[4.5.0, )"
|
||||
}
|
||||
},
|
||||
"mysqlmigrations": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "[2022.10.0, )",
|
||||
"Infrastructure.EntityFramework": "[2022.10.0, )"
|
||||
}
|
||||
},
|
||||
"postgresmigrations": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "[2022.10.0, )",
|
||||
"Infrastructure.EntityFramework": "[2022.10.0, )"
|
||||
}
|
||||
},
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2022.8.4",
|
||||
"Infrastructure.Dapper": "2022.8.4",
|
||||
"Infrastructure.EntityFramework": "2022.8.4"
|
||||
"Core": "[2022.10.0, )",
|
||||
"Infrastructure.Dapper": "[2022.10.0, )",
|
||||
"Infrastructure.EntityFramework": "[2022.10.0, )"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ public class Startup
|
||||
StripeConfiguration.MaxNetworkRetries = globalSettings.Stripe.MaxNetworkRetries;
|
||||
|
||||
// Repositories
|
||||
services.AddSqlServerRepositories(globalSettings);
|
||||
services.AddDatabaseRepositories(globalSettings);
|
||||
|
||||
// Context
|
||||
services.AddScoped<ICurrentContext, CurrentContext>();
|
||||
|
@ -34,7 +34,7 @@ public class Startup
|
||||
StripeConfiguration.MaxNetworkRetries = globalSettings.Stripe.MaxNetworkRetries;
|
||||
|
||||
// Repositories
|
||||
services.AddSqlServerRepositories(globalSettings);
|
||||
services.AddDatabaseRepositories(globalSettings);
|
||||
|
||||
// PayPal Client
|
||||
services.AddSingleton<Utilities.PayPalIpnClient>();
|
||||
|
@ -24,6 +24,7 @@ public class GlobalSettings : IGlobalSettings
|
||||
get => BuildDirectory(_logDirectory, "/logs");
|
||||
set => _logDirectory = value;
|
||||
}
|
||||
public virtual bool LogDirectoryByProject { get; set; } = true;
|
||||
public virtual long? LogRollBySizeLimit { get; set; }
|
||||
public virtual bool EnableDevLogging { get; set; } = false;
|
||||
public virtual string LicenseDirectory
|
||||
|
7
src/Core/Utilities/IDbMigrator.cs
Normal file
7
src/Core/Utilities/IDbMigrator.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Bit.Core.Utilities;
|
||||
|
||||
public interface IDbMigrator
|
||||
{
|
||||
bool MigrateDatabase(bool enableLogging = true,
|
||||
CancellationToken cancellationToken = default(CancellationToken));
|
||||
}
|
@ -125,13 +125,22 @@ public static class LoggerFactoryExtensions
|
||||
{
|
||||
if (globalSettings.LogRollBySizeLimit.HasValue)
|
||||
{
|
||||
config.WriteTo.File($"{globalSettings.LogDirectory}/{globalSettings.ProjectName}/log.txt",
|
||||
rollOnFileSizeLimit: true, fileSizeLimitBytes: globalSettings.LogRollBySizeLimit);
|
||||
var pathFormat = Path.Combine(globalSettings.LogDirectory, $"{globalSettings.ProjectName.ToLowerInvariant()}.log");
|
||||
if (globalSettings.LogDirectoryByProject)
|
||||
{
|
||||
pathFormat = Path.Combine(globalSettings.LogDirectory, globalSettings.ProjectName, "log.txt");
|
||||
}
|
||||
config.WriteTo.File(pathFormat, rollOnFileSizeLimit: true,
|
||||
fileSizeLimitBytes: globalSettings.LogRollBySizeLimit);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.WriteTo
|
||||
.RollingFile($"{globalSettings.LogDirectory}/{globalSettings.ProjectName}/{{Date}}.txt");
|
||||
var pathFormat = Path.Combine(globalSettings.LogDirectory, $"{globalSettings.ProjectName.ToLowerInvariant()}_{{Date}}.log");
|
||||
if (globalSettings.LogDirectoryByProject)
|
||||
{
|
||||
pathFormat = Path.Combine(globalSettings.LogDirectory, globalSettings.ProjectName, "{Date}.txt");
|
||||
}
|
||||
config.WriteTo.RollingFile(pathFormat);
|
||||
}
|
||||
config
|
||||
.Enrich.FromLogContext()
|
||||
|
@ -29,7 +29,7 @@ public class Startup
|
||||
var globalSettings = services.AddGlobalSettingsServices(Configuration, Environment);
|
||||
|
||||
// Repositories
|
||||
services.AddSqlServerRepositories(globalSettings);
|
||||
services.AddDatabaseRepositories(globalSettings);
|
||||
|
||||
// Context
|
||||
services.AddScoped<ICurrentContext, CurrentContext>();
|
||||
|
@ -44,7 +44,7 @@ public class Startup
|
||||
services.AddCustomDataProtectionServices(Environment, globalSettings);
|
||||
|
||||
// Repositories
|
||||
services.AddSqlServerRepositories(globalSettings);
|
||||
services.AddDatabaseRepositories(globalSettings);
|
||||
|
||||
// Context
|
||||
services.AddScoped<ICurrentContext, CurrentContext>();
|
||||
|
@ -22,13 +22,14 @@ public static class EntityFrameworkServiceCollectionExtensions
|
||||
{
|
||||
if (provider == SupportedDatabaseProviders.Postgres)
|
||||
{
|
||||
options.UseNpgsql(connectionString);
|
||||
options.UseNpgsql(connectionString, b => b.MigrationsAssembly("PostgresMigrations"));
|
||||
// Handle NpgSql Legacy Support for `timestamp without timezone` issue
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
}
|
||||
else if (provider == SupportedDatabaseProviders.MySql)
|
||||
{
|
||||
options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
|
||||
options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString),
|
||||
b => b.MigrationsAssembly("MySqlMigrations"));
|
||||
}
|
||||
});
|
||||
services.AddSingleton<ICipherRepository, CipherRepository>();
|
||||
|
@ -47,7 +47,7 @@ namespace Bit.SharedWeb.Utilities;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static void AddSqlServerRepositories(this IServiceCollection services, GlobalSettings globalSettings)
|
||||
public static SupportedDatabaseProviders AddDatabaseRepositories(this IServiceCollection services, GlobalSettings globalSettings)
|
||||
{
|
||||
var selectedDatabaseProvider = globalSettings.DatabaseProvider;
|
||||
var provider = SupportedDatabaseProviders.SqlServer;
|
||||
@ -93,6 +93,8 @@ public static class ServiceCollectionExtensions
|
||||
services.AddSingleton<IInstallationDeviceRepository, TableStorageRepos.InstallationDeviceRepository>();
|
||||
services.AddSingleton<IMetaDataRepository, TableStorageRepos.MetaDataRepository>();
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static void AddBaseServices(this IServiceCollection services, IGlobalSettings globalSettings)
|
||||
|
@ -1,13 +1,11 @@
|
||||
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Bit;
|
||||
namespace Bit.EfShared;
|
||||
|
||||
// This file is a manual addition to a project that it helps, a project that chooses to compile it
|
||||
// should have a projet reference to Core.csproj and a package reference to Microsoft.EntityFrameworkCore.Design
|
||||
// should have a project reference to Core.csproj and a package reference to Microsoft.EntityFrameworkCore.Design
|
||||
// The reason for this is that if it belonged to it's own library you would have to add manual references to the above
|
||||
// and manage the version for the EntityFrameworkCore package. This way it also doesn't create another dll
|
||||
// To include this you can view examples in the MySqlMigrations and PostgresMigrations .csproj files.
|
||||
|
109
util/Migrator/SqlServerDbMigrator.cs
Normal file
109
util/Migrator/SqlServerDbMigrator.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Reflection;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using DbUp;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Migrator;
|
||||
|
||||
public class SqlServerDbMigrator : IDbMigrator
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private readonly ILogger<SqlServerDbMigrator> _logger;
|
||||
private readonly string _masterConnectionString;
|
||||
|
||||
public SqlServerDbMigrator(GlobalSettings globalSettings, ILogger<SqlServerDbMigrator> logger)
|
||||
{
|
||||
_connectionString = globalSettings.SqlServer.ConnectionString;
|
||||
_logger = logger;
|
||||
_masterConnectionString = new SqlConnectionStringBuilder(_connectionString)
|
||||
{
|
||||
InitialCatalog = "master"
|
||||
}.ConnectionString;
|
||||
}
|
||||
|
||||
public bool MigrateDatabase(bool enableLogging = true,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (enableLogging && _logger != null)
|
||||
{
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Migrating database.");
|
||||
}
|
||||
|
||||
using (var connection = new SqlConnection(_masterConnectionString))
|
||||
{
|
||||
var databaseName = new SqlConnectionStringBuilder(_connectionString).InitialCatalog;
|
||||
if (string.IsNullOrWhiteSpace(databaseName))
|
||||
{
|
||||
databaseName = "vault";
|
||||
}
|
||||
|
||||
var databaseNameQuoted = new SqlCommandBuilder().QuoteIdentifier(databaseName);
|
||||
var command = new SqlCommand(
|
||||
"IF ((SELECT COUNT(1) FROM sys.databases WHERE [name] = @DatabaseName) = 0) " +
|
||||
"CREATE DATABASE " + databaseNameQuoted + ";", connection);
|
||||
command.Parameters.Add("@DatabaseName", SqlDbType.VarChar).Value = databaseName;
|
||||
command.Connection.Open();
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
command.CommandText = "IF ((SELECT DATABASEPROPERTYEX([name], 'IsAutoClose') " +
|
||||
"FROM sys.databases WHERE [name] = @DatabaseName) = 1) " +
|
||||
"ALTER DATABASE " + databaseNameQuoted + " SET AUTO_CLOSE OFF;";
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
// Rename old migration scripts to new namespace.
|
||||
var command = new SqlCommand(
|
||||
"IF OBJECT_ID('Migration','U') IS NOT NULL " +
|
||||
"UPDATE [dbo].[Migration] SET " +
|
||||
"[ScriptName] = REPLACE([ScriptName], 'Bit.Setup.', 'Bit.Migrator.');", connection);
|
||||
command.Connection.Open();
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var builder = DeployChanges.To
|
||||
.SqlDatabase(_connectionString)
|
||||
.JournalToSqlTable("dbo", "Migration")
|
||||
.WithScriptsAndCodeEmbeddedInAssembly(Assembly.GetExecutingAssembly(),
|
||||
s => s.Contains($".DbScripts.") && !s.Contains(".Archive."))
|
||||
.WithTransaction()
|
||||
.WithExecutionTimeout(TimeSpan.FromMinutes(5));
|
||||
|
||||
if (enableLogging)
|
||||
{
|
||||
if (_logger != null)
|
||||
{
|
||||
builder.LogTo(new DbUpLogger(_logger));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.LogToConsole();
|
||||
}
|
||||
}
|
||||
|
||||
var upgrader = builder.Build();
|
||||
var result = upgrader.PerformUpgrade();
|
||||
|
||||
if (enableLogging && _logger != null)
|
||||
{
|
||||
if (result.Successful)
|
||||
{
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Migration successful.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError(Constants.BypassFiltersEventId, result.Error, "Migration failed.");
|
||||
}
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return result.Successful;
|
||||
}
|
||||
}
|
@ -46,6 +46,23 @@
|
||||
"StackExchange.Redis": "2.5.43"
|
||||
}
|
||||
},
|
||||
"AutoMapper": {
|
||||
"type": "Transitive",
|
||||
"resolved": "11.0.0",
|
||||
"contentHash": "+596AnKykYCk9RxXCEF4GYuapSebQtFVvIA1oVG1rrRkCLAC7AkWehJ0brCfYUbdDW3v1H/p0W3hob7JoXGjMw==",
|
||||
"dependencies": {
|
||||
"Microsoft.CSharp": "4.7.0"
|
||||
}
|
||||
},
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "11.0.0",
|
||||
"contentHash": "0asw5WxdCFh2OTi9Gv+oKyH9SzxwYQSnO8TV5Dd0GggovILzJW4UimP26JAcxc3yB5NnC5urooZ1BBs8ElpiBw==",
|
||||
"dependencies": {
|
||||
"AutoMapper": "11.0.0",
|
||||
"Microsoft.Extensions.Options": "6.0.0"
|
||||
}
|
||||
},
|
||||
"AWSSDK.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.7.10.11",
|
||||
@ -246,6 +263,23 @@
|
||||
"Microsoft.NETCore.Platforms": "1.0.1"
|
||||
}
|
||||
},
|
||||
"linq2db": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.7.0",
|
||||
"contentHash": "iDous2TbSchtALnTLNXQnprmNZF4GrXas0MBz6ZHWkSdilSJjcf26qFM7Qf98Mny0OXHEmNXG/jtIDhoVJ5KmQ==",
|
||||
"dependencies": {
|
||||
"System.ComponentModel.Annotations": "4.7.0"
|
||||
}
|
||||
},
|
||||
"linq2db.EntityFrameworkCore": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.7.1",
|
||||
"contentHash": "Bb25vUDyFw3nKnf7KY+bauwKGD0hdM7/syodS+IgHdWlcbH9g7tHxYmMa9+DNuL0yy6DFvP6Q3BkClm7zbQdAw==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.0",
|
||||
"linq2db": "3.7.0"
|
||||
}
|
||||
},
|
||||
"MailKit": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.2.0",
|
||||
@ -474,6 +508,39 @@
|
||||
"resolved": "4.0.0",
|
||||
"contentHash": "wtLlRwQX7YoBUYm25xBjJ3UsuLgycme1xXqDn8t3S5kPCWiZrx8uOkyZHLKzH4kkCiQ9m2/J5JeCKNRbZNn3Qg=="
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "gTh3SJsF5WNjEmG32kYc3U4tjeTIv55QOrwHAJcF/xtrIVMteDHMArGC35N0dw86WFY0v8yFkKYKOIOln4jkfQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore.Abstractions": "6.0.4",
|
||||
"Microsoft.EntityFrameworkCore.Analyzers": "6.0.4",
|
||||
"Microsoft.Extensions.Caching.Memory": "6.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection": "6.0.0",
|
||||
"Microsoft.Extensions.Logging": "6.0.0",
|
||||
"System.Collections.Immutable": "6.0.0",
|
||||
"System.Diagnostics.DiagnosticSource": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "jycTQF0FUJp10cGWBmtsyFhQNeISU9CltDRKCaNiX4QRSEFzgRgaFN4vAFK0T+G5etmXugyddijE4NWCGtgznQ=="
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Analyzers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "t12WodVyGGP2CuLo7R1qwcawHY5zlg+GiQzvkceZpsjcFJVyTFFBFDPg1isBtzurLzWsl+G3z5fVXeic90mPxg=="
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Relational": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "E867NbEXYRTElBF5ff+1AN5Awa1jkORy/Rrm0ueibaTAV5uw89LsLoH6yTe+b9urZTWMHtLfGd1RDdNjk8+KzA==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore": "6.0.4",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Caching.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
@ -484,13 +551,14 @@
|
||||
},
|
||||
"Microsoft.Extensions.Caching.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.8",
|
||||
"contentHash": "u04q7+tgc8l6pQ5HOcr6scgapkQQHnrhpGoCaaAZd24R36/NxGsGxuhSmhHOrQx9CsBLe2CVBN/4CkLlxtnnXw==",
|
||||
"resolved": "6.0.1",
|
||||
"contentHash": "B4y+Cev05eMcjf1na0v9gza6GUtahXbtY1JCypIgx3B4Ea/KAgsWyXEmW4q6zMbmTMtKzmPVk09rvFJirvMwTg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Caching.Abstractions": "3.1.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "3.1.8",
|
||||
"Microsoft.Extensions.Options": "3.1.8"
|
||||
"Microsoft.Extensions.Caching.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.Options": "6.0.0",
|
||||
"Microsoft.Extensions.Primitives": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Caching.StackExchangeRedis": {
|
||||
@ -811,6 +879,11 @@
|
||||
"System.Security.Cryptography.Pkcs": "6.0.0"
|
||||
}
|
||||
},
|
||||
"MySqlConnector": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.2",
|
||||
"contentHash": "JVokQTUNN3WHAu9Vw8ieeq1dXTFokJiig5P0VJ4f439UxRrsPo6SaVWC8Zdm6mkPeQFhZ0/9afdWa02EY/1j/w=="
|
||||
},
|
||||
"NETStandard.Library": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.6.1",
|
||||
@ -867,6 +940,25 @@
|
||||
"resolved": "13.0.1",
|
||||
"contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
|
||||
},
|
||||
"Npgsql": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "SJMlOmFHr32oOzVXeHmarGaBKkhi0wHVN/rzuu2tUSJ4Qx2AkHCpr9R/DhLWwDiklqgzFU++9wkFyGJxbx/zzg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "fzgRmBd3nAFvKt/L70sJfFWAdobtwDEeOzOzruJq9og97O8/5B96inQOAgOpYyaUjPYpS4ZS5/bxm3vnOJ0+pQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore": "6.0.4",
|
||||
"Microsoft.EntityFrameworkCore.Abstractions": "6.0.4",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.4",
|
||||
"Npgsql": "6.0.4"
|
||||
}
|
||||
},
|
||||
"NSec.Cryptography": {
|
||||
"type": "Transitive",
|
||||
"resolved": "20.2.0",
|
||||
@ -889,6 +981,16 @@
|
||||
"System.IO.Pipelines": "5.0.1"
|
||||
}
|
||||
},
|
||||
"Pomelo.EntityFrameworkCore.MySql": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.1",
|
||||
"contentHash": "sFIo5e9RmQoCTEvH6EeSV8ptmX3dw/6XgyD8R93X/i7A9+XCeG9KTjSNjrszVjVOtCu/eyvYqqcv2uZ/BHhlYA==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[6.0.1, 7.0.0)",
|
||||
"Microsoft.Extensions.DependencyInjection": "6.0.0",
|
||||
"MySqlConnector": "2.1.2"
|
||||
}
|
||||
},
|
||||
"Portable.BouncyCastle": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.9.0",
|
||||
@ -1281,8 +1383,11 @@
|
||||
},
|
||||
"System.Collections.Immutable": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.7.0",
|
||||
"contentHash": "RVSM6wZUo6L2y6P3vN6gjUtyJ2IF2RVtrepF3J7nrDKfFQd5u/SnSUFclchYQis8/k5scHy9E+fVeKVQLnnkzw=="
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"System.Collections.NonGeneric": {
|
||||
"type": "Transitive",
|
||||
@ -1311,6 +1416,11 @@
|
||||
"System.Threading": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.ComponentModel.Annotations": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "0YFqjhp/mYkDGpU0Ye1GjE53HMp9UVfGN7seGpAMttAC0C40v5gw598jCgpbBLMmCo0E5YRLBv5Z2doypO49ZQ=="
|
||||
},
|
||||
"System.Configuration.ConfigurationManager": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
@ -2579,41 +2689,52 @@
|
||||
"core": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AWSSDK.SQS": "3.7.2.47",
|
||||
"AWSSDK.SimpleEmail": "3.7.0.150",
|
||||
"AspNetCoreRateLimit": "4.0.2",
|
||||
"AspNetCoreRateLimit.Redis": "1.0.1",
|
||||
"Azure.Extensions.AspNetCore.DataProtection.Blobs": "1.2.1",
|
||||
"Azure.Storage.Blobs": "12.11.0",
|
||||
"Azure.Storage.Queues": "12.9.0",
|
||||
"BitPay.Light": "1.0.1907",
|
||||
"Braintree": "5.12.0",
|
||||
"Fido2.AspNet": "3.0.0-beta2",
|
||||
"Handlebars.Net": "2.1.2",
|
||||
"IdentityServer4": "4.1.2",
|
||||
"IdentityServer4.AccessTokenValidation": "3.0.1",
|
||||
"MailKit": "3.2.0",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "6.0.4",
|
||||
"Microsoft.Azure.Cosmos.Table": "1.0.8",
|
||||
"Microsoft.Azure.NotificationHubs": "4.1.0",
|
||||
"Microsoft.Azure.ServiceBus": "5.2.0",
|
||||
"Microsoft.Data.SqlClient": "4.1.0",
|
||||
"Microsoft.Extensions.Caching.StackExchangeRedis": "6.0.6",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "6.0.1",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "6.0.1",
|
||||
"Microsoft.Extensions.Identity.Stores": "6.0.4",
|
||||
"Newtonsoft.Json": "13.0.1",
|
||||
"Otp.NET": "1.2.2",
|
||||
"Quartz": "3.4.0",
|
||||
"SendGrid": "9.27.0",
|
||||
"Sentry.Serilog": "3.16.0",
|
||||
"Serilog.AspNetCore": "5.0.0",
|
||||
"Serilog.Extensions.Logging": "3.1.0",
|
||||
"Serilog.Extensions.Logging.File": "2.0.0",
|
||||
"Serilog.Sinks.AzureCosmosDB": "2.0.0",
|
||||
"Serilog.Sinks.SyslogMessages": "2.0.6",
|
||||
"Stripe.net": "40.0.0",
|
||||
"YubicoDotNetClient": "1.2.0"
|
||||
"AWSSDK.SQS": "[3.7.2.47, )",
|
||||
"AWSSDK.SimpleEmail": "[3.7.0.150, )",
|
||||
"AspNetCoreRateLimit": "[4.0.2, )",
|
||||
"AspNetCoreRateLimit.Redis": "[1.0.1, )",
|
||||
"Azure.Extensions.AspNetCore.DataProtection.Blobs": "[1.2.1, )",
|
||||
"Azure.Storage.Blobs": "[12.11.0, )",
|
||||
"Azure.Storage.Queues": "[12.9.0, )",
|
||||
"BitPay.Light": "[1.0.1907, )",
|
||||
"Braintree": "[5.12.0, )",
|
||||
"Fido2.AspNet": "[3.0.0-beta2, )",
|
||||
"Handlebars.Net": "[2.1.2, )",
|
||||
"IdentityServer4": "[4.1.2, )",
|
||||
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
|
||||
"MailKit": "[3.2.0, )",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
|
||||
"Microsoft.Azure.Cosmos.Table": "[1.0.8, )",
|
||||
"Microsoft.Azure.NotificationHubs": "[4.1.0, )",
|
||||
"Microsoft.Azure.ServiceBus": "[5.2.0, )",
|
||||
"Microsoft.Data.SqlClient": "[4.1.0, )",
|
||||
"Microsoft.Extensions.Caching.StackExchangeRedis": "[6.0.6, )",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "[6.0.1, )",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "[6.0.1, )",
|
||||
"Microsoft.Extensions.Identity.Stores": "[6.0.4, )",
|
||||
"Newtonsoft.Json": "[13.0.1, )",
|
||||
"Otp.NET": "[1.2.2, )",
|
||||
"Quartz": "[3.4.0, )",
|
||||
"SendGrid": "[9.27.0, )",
|
||||
"Sentry.Serilog": "[3.16.0, )",
|
||||
"Serilog.AspNetCore": "[5.0.0, )",
|
||||
"Serilog.Extensions.Logging": "[3.1.0, )",
|
||||
"Serilog.Extensions.Logging.File": "[2.0.0, )",
|
||||
"Serilog.Sinks.AzureCosmosDB": "[2.0.0, )",
|
||||
"Serilog.Sinks.SyslogMessages": "[2.0.6, )",
|
||||
"Stripe.net": "[40.0.0, )",
|
||||
"YubicoDotNetClient": "[1.2.0, )"
|
||||
}
|
||||
},
|
||||
"infrastructure.entityframework": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[11.0.0, )",
|
||||
"Core": "[2022.10.0, )",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[6.0.4, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "[6.0.4, )",
|
||||
"Pomelo.EntityFrameworkCore.MySql": "[6.0.1, )",
|
||||
"linq2db.EntityFrameworkCore": "[6.7.1, )"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,15 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace MySqlMigrations;
|
||||
namespace Bit.MySqlMigrations;
|
||||
|
||||
public static class GlobalSettingsFactory
|
||||
{
|
||||
public static GlobalSettings GlobalSettings { get; } = new GlobalSettings();
|
||||
static GlobalSettingsFactory()
|
||||
{
|
||||
var configBuilder = new ConfigurationBuilder().AddUserSecrets<Bit.Api.Startup>();
|
||||
// UserSecretsId here should match what is in Api.csproj
|
||||
var configBuilder = new ConfigurationBuilder().AddUserSecrets("bitwarden-Api");
|
||||
var Configuration = configBuilder.Build();
|
||||
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Bit.EfShared;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Bit.MySqlMigrations.Migrations;
|
||||
|
||||
|
41
util/MySqlMigrations/MySqlDbMigrator.cs
Normal file
41
util/MySqlMigrations/MySqlDbMigrator.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Bit.Core;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.MySqlMigrations;
|
||||
|
||||
public class MySqlDbMigrator : IDbMigrator
|
||||
{
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private readonly ILogger<MySqlDbMigrator> _logger;
|
||||
|
||||
public MySqlDbMigrator(IServiceScopeFactory serviceScopeFactory, ILogger<MySqlDbMigrator> logger)
|
||||
{
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool MigrateDatabase(bool enableLogging = true,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (enableLogging && _logger != null)
|
||||
{
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Migrating database.");
|
||||
}
|
||||
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var databaseContext = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||
databaseContext.Database.Migrate();
|
||||
|
||||
if (enableLogging && _logger != null)
|
||||
{
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Migration successful.");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<UserSecretsId>9f1cd3e0-70f2-4921-8068-b2538fd7c3f7</UserSecretsId>
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Core\Core.csproj" />
|
||||
<ProjectReference Include="..\..\src\Api\Api.csproj" />
|
||||
<ProjectReference Include="..\..\src\Infrastructure.EntityFramework\Infrastructure.EntityFramework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -4,14 +4,15 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace MySqlMigrations;
|
||||
namespace Bit.PostgresMigrations;
|
||||
|
||||
public static class GlobalSettingsFactory
|
||||
{
|
||||
public static GlobalSettings GlobalSettings { get; } = new GlobalSettings();
|
||||
static GlobalSettingsFactory()
|
||||
{
|
||||
var configBuilder = new ConfigurationBuilder().AddUserSecrets<Bit.Api.Startup>();
|
||||
// UserSecretsId here should match what is in Api.csproj
|
||||
var configBuilder = new ConfigurationBuilder().AddUserSecrets("bitwarden-Api");
|
||||
var Configuration = configBuilder.Build();
|
||||
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Bit.EfShared;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Bit.PostgresMigrations.Migrations;
|
||||
|
||||
|
41
util/PostgresMigrations/PostgresDbMigratorDbMigrator.cs
Normal file
41
util/PostgresMigrations/PostgresDbMigratorDbMigrator.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Bit.Core;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.PostgresMigrations;
|
||||
|
||||
public class PostgresDbMigrator : IDbMigrator
|
||||
{
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private readonly ILogger<PostgresDbMigrator> _logger;
|
||||
|
||||
public PostgresDbMigrator(IServiceScopeFactory serviceScopeFactory, ILogger<PostgresDbMigrator> logger)
|
||||
{
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool MigrateDatabase(bool enableLogging = true,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (enableLogging && _logger != null)
|
||||
{
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Migrating database.");
|
||||
}
|
||||
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var databaseContext = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||
databaseContext.Database.Migrate();
|
||||
|
||||
if (enableLogging && _logger != null)
|
||||
{
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Migration successful.");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return true;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Core\Core.csproj" />
|
||||
<ProjectReference Include="..\..\src\Api\Api.csproj" />
|
||||
<ProjectReference Include="..\..\src\Infrastructure.EntityFramework\Infrastructure.EntityFramework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user