From ee8b0a25a848c54759fc37343a848d4ec39d2027 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Mon, 7 Aug 2017 11:24:16 -0400 Subject: [PATCH] setup, build, and run scripts --- build.ps1 | 9 ++++ build.sh | 11 +++++ docker/docker-compose.linux.yml | 15 +++++++ docker/docker-compose.override.yml | 11 +++++ docker/docker-compose.prod.yml | 0 docker/docker-compose.windows.yml | 17 ++++++++ docker/docker-compose.yml | 17 ++------ docker/global.env | 2 +- nginx/build.ps1 | 7 ++++ nginx/build.sh | 10 +++++ scripts/install.sh | 11 ----- scripts/run.ps1 | 7 ++++ scripts/run.sh | 10 +++++ scripts/setup.ps1 | 37 ++++++++++++++++ scripts/setup.sh | 42 +++++++++++++++++++ src/Api/Dockerfile | 3 +- src/Api/build.ps1 | 11 +++++ src/Api/build.sh | 14 +++++++ src/Core/GlobalSettings.cs | 1 + src/Core/Utilities/CoreHelpers.cs | 7 +++- .../Utilities/ServiceCollectionExtensions.cs | 9 +++- src/Identity/.dockerignore | 1 + src/Identity/Dockerfile | 8 ++-- src/Identity/build.ps1 | 11 +++++ src/Identity/build.sh | 14 +++++++ src/Identity/entrypoint.sh | 5 +++ 26 files changed, 257 insertions(+), 33 deletions(-) create mode 100644 build.ps1 create mode 100644 build.sh create mode 100644 docker/docker-compose.linux.yml create mode 100644 docker/docker-compose.override.yml create mode 100644 docker/docker-compose.prod.yml create mode 100644 docker/docker-compose.windows.yml create mode 100644 nginx/build.ps1 create mode 100644 nginx/build.sh delete mode 100644 scripts/install.sh create mode 100644 scripts/run.ps1 create mode 100644 scripts/run.sh create mode 100644 scripts/setup.ps1 create mode 100644 scripts/setup.sh create mode 100644 src/Api/build.ps1 create mode 100644 src/Api/build.sh create mode 100644 src/Identity/build.ps1 create mode 100644 src/Identity/build.sh create mode 100644 src/Identity/entrypoint.sh diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..74b93fdd2c --- /dev/null +++ b/build.ps1 @@ -0,0 +1,9 @@ +$dir = Split-Path -Parent $MyInvocation.MyCommand.Path +echo $dir + +echo "`nBuilding bitwarden" +echo "==================" + +& $dir\src\Api\build.ps1 +& $dir\src\Identity\build.ps1 +& $dir\nginx\build.ps1 diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000..ca0a3c02b0 --- /dev/null +++ b/build.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -e + +DIR="$(dirname $(readlink -f $0))" + +echo -e "\nBuilding bitwarden" +echo -e "==================" + +$DIR/src/Api/build.sh +$DIR/src/Identity/build.sh +$DIR/nginx/build.sh diff --git a/docker/docker-compose.linux.yml b/docker/docker-compose.linux.yml new file mode 100644 index 0000000000..3bf7a1ab5b --- /dev/null +++ b/docker/docker-compose.linux.yml @@ -0,0 +1,15 @@ +version: '3' + +services: + mssql: + volumes: + - /etc/bitwarden/mssql_data:/var/opt/mssql/data + api: + volumes: + - /etc/bitwarden/core:/etc/core + identity: + volumes: + - /etc/bitwarden/core:/etc/core + nginx: + volumes: + - /etc/bitwarden/letsencrypt:/etc/letsencrypt diff --git a/docker/docker-compose.override.yml b/docker/docker-compose.override.yml new file mode 100644 index 0000000000..4e08d1063e --- /dev/null +++ b/docker/docker-compose.override.yml @@ -0,0 +1,11 @@ +version: '3' + +services: + mssql: + volumes: + - mssql_data:/var/opt/mssql/data + nginx: + volumes: + - c:/bitwarden/letsencrypt:/etc/letsencrypt +volumes: + mssql_data: diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docker/docker-compose.windows.yml b/docker/docker-compose.windows.yml new file mode 100644 index 0000000000..e6c3e498fc --- /dev/null +++ b/docker/docker-compose.windows.yml @@ -0,0 +1,17 @@ +version: '3' + +services: + mssql: + volumes: + - mssql_data:/var/opt/mssql/data + api: + volumes: + - c:/bitwarden/core:/etc/core + identity: + volumes: + - c:/bitwarden/core:/etc/core + nginx: + volumes: + - c:/bitwarden/letsencrypt:/etc/letsencrypt +volumes: + mssql_data: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index f6a54c12a8..f87f22848a 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -5,8 +5,6 @@ services: image: microsoft/mssql-server-linux container_name: mssql restart: always - volumes: - - mssql_data:/var/opt/mssql/data env_file: - mssql.env - mssql.override.env @@ -14,33 +12,24 @@ services: - '1433:1433' api: - image: api + image: bitwarden/api container_name: api restart: always - build: ../src/Api env_file: - global.env - global.override.env identity: - image: identity + image: bitwarden/identity container_name: identity - restart: always - build: ../src/Identity env_file: - global.env - global.override.env nginx: - image: nginx + image: bitwarden/nginx container_name: nginx restart: always - build: ../nginx - volumes: - - c:/bitwarden/letsencrypt:/etc/letsencrypt ports: - '80:80' - '443:443' - -volumes: - mssql_data: diff --git a/docker/global.env b/docker/global.env index e92cb6651c..871ee20b24 100644 --- a/docker/global.env +++ b/docker/global.env @@ -3,4 +3,4 @@ globalSettings:selfHosted=true globalSettings:baseServiceUri:vault=http://localhost globalSettings:baseServiceUri:api=http://localhost/api globalSettings:baseServiceUri:identity=http://localhost/identity -globalSettings:baseServiceUri:identityInternal=http://identity +globalSettings:baseServiceUri:internalIdentity=http://identity diff --git a/nginx/build.ps1 b/nginx/build.ps1 new file mode 100644 index 0000000000..4857456ce5 --- /dev/null +++ b/nginx/build.ps1 @@ -0,0 +1,7 @@ +$dir = Split-Path -Parent $MyInvocation.MyCommand.Path + +echo "`n# Building nginx" + +echo "`nBuilding docker image" +docker --version +docker build -t bitwarden/nginx $dir\. diff --git a/nginx/build.sh b/nginx/build.sh new file mode 100644 index 0000000000..b0ebfe36a1 --- /dev/null +++ b/nginx/build.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e + +DIR="$(dirname $(readlink -f $0))" + +echo -e "\n# Building nginx" + +echo -e "\nBuilding docker image" +docker --version +docker build -t bitwarden/nginx $DIR/. diff --git a/scripts/install.sh b/scripts/install.sh deleted file mode 100644 index f10d683dac..0000000000 --- a/scripts/install.sh +++ /dev/null @@ -1,11 +0,0 @@ -dotnet publish ../src/Api/Api.csproj -f netcoreapp2.0 -o obj/Docker/publish -c "Release" -dotnet publish ../src/Identity/Identity.csproj -f netcoreapp2.0 -o obj/Docker/publish -c "Release" - -docker-compose pull -docker-compose down - -#mkdir -p c:/bitwarden/letsencrypt/live -#docker run -it --rm -p 80:80 -v c:/bitwarden/letsencrypt:/etc/letsencrypt/ certbot/certbot certonly --standalone --noninteractive --preferred-challenges http --email kyle.spearrin@gmail.com --agree-tos -d bw.kylespearrin.com -#openssl dhparam -out c:/bitwarden/letsencrypt/live/bw.kylespearrin.com/dhparam.pem 2048 - -docker-compose up -d diff --git a/scripts/run.ps1 b/scripts/run.ps1 new file mode 100644 index 0000000000..577f06f211 --- /dev/null +++ b/scripts/run.ps1 @@ -0,0 +1,7 @@ +$dockerDir="../docker" + +docker --version +docker-compose --version + +docker-compose -f $dockerDir/docker-compose.yml -f $dockerDir/docker-compose.windows.yml down +docker-compose -f $dockerDir/docker-compose.yml -f $dockerDir/docker-compose.windows.yml up -d diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100644 index 0000000000..4f7c4877e8 --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e + +DOCKER_DIR=../docker + +docker --version +docker-compose --version + +docker-compose -f $DOCKER_DIR/docker-compose.yml -f $DOCKER_DIR/docker-compose.windows.yml down +docker-compose -f $DOCKER_DIR/docker-compose.yml -f $DOCKER_DIR/docker-compose.windows.yml up -d diff --git a/scripts/setup.ps1 b/scripts/setup.ps1 new file mode 100644 index 0000000000..1f6413de68 --- /dev/null +++ b/scripts/setup.ps1 @@ -0,0 +1,37 @@ +param ( + [string]$outputDir = "c:/bitwarden", + [string]$domain = $( Read-Host "Please enter your domain name (i.e. bitwarden.company.com)" ), + [string]$email = $( Read-Host "Please enter your email address (used to generate an HTTPS certificate with LetsEncrypt)" ) +) + +$dockerDir="../docker" +$certPassword=-join ((48..57) + (97..122) | Get-Random -Count 32 | % {[char]$_}) +$databasePassword=-join ((48..57) + (97..122) | Get-Random -Count 32 | % {[char]$_}) +$duoKey=-join ((48..57) + (97..122) | Get-Random -Count 32 | % {[char]$_}) + +docker --version + +#mkdir -p $outputDir/letsencrypt/live/$domain +#docker run -it --rm -p 80:80 -v $outputDir/letsencrypt:/etc/letsencrypt/ certbot/certbot certonly --standalone --noninteractive --preferred-challenges http --email $email --agree-tos -d $domain +#docker run -it --rm -v $outputDir/letsencrypt/live:/certificates/ bitwarden/openssl openssl dhparam -out /certificates/$domain/dhparam.pem 2048 + +mkdir -p $outputDir/core +docker run -it --rm -v $outputDir/core:/certificates bitwarden/openssl openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout /certificates/identity.key -out /certificates/identity.crt -subj "/CN=bitwarden IdentityServer" -days 10950 +docker run -it --rm -v $outputDir/core:/certificates bitwarden/openssl openssl pkcs12 -export -out /certificates/identity.pfx -inkey /certificates/identity.key -in /certificates/identity.crt -certfile /certificates/identity.crt -passout pass:$certPassword +rm $outputDir/core/identity.key +rm $outputDir/core/identity.crt + +Add-Content $dockerDir/global.override.env " +globalSettings:baseServiceUri:vault=https://$domain +globalSettings:baseServiceUri:api=https://$domain/api +globalSettings:baseServiceUri:identity=https://$domain/identity +globalSettings:sqlServer:connectionString=Server=tcp:mssql,1433;Initial Catalog=vault;Persist Security Info=False;User ID=sa;Password=$databasePassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30; +globalSettings:identityServer:certificatePassword=$certPassword +globalSettings:duo:aKey=$duoKey +globalSettings:yubico:clientId=REPLACE +globalSettings:yubico:REPLACE" + +Add-Content $dockerDir/mssql.override.env " +ACCEPT_EULA=Y +MSSQL_PID=Express +SA_PASSWORD=$databasePassword" diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100644 index 0000000000..b447cbf3a3 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -e + +echo "Please enter your domain name (i.e. bitwarden.company.com): " +read DOMAIN +echo -e "\nPlease enter your email address (used to generate an HTTPS certificate with LetsEncrypt): " +read EMAIL + +OUTPUT_DIR=./bitwarden +DOCKER_DIR=../docker +CERT_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > $DOCKER_DIR/global.override.env << EOF +globalSettings:baseServiceUri:vault=https://$DOMAIN +globalSettings:baseServiceUri:api=https://$DOMAIN/api +globalSettings:baseServiceUri:identity=https://$DOMAIN/identity +globalSettings:sqlServer:connectionString=Server=tcp:mssql,1433;Initial Catalog=vault;Persist Security Info=False;User ID=sa;Password=$DATABASE_PASSWORD;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30; +globalSettings:identityServer:certificatePassword=$CERT_PASSWORD +globalSettings:duo:aKey=$DUO_KEY +globalSettings:yubico:clientId=REPLACE +globalSettings:yubico:REPLACE +EOF + +cat >> $DOCKER_DIR/mssql.override.env << EOF +ACCEPT_EULA=Y +MSSQL_PID=Express +SA_PASSWORD=$DATABASE_PASSWORD +EOF \ No newline at end of file diff --git a/src/Api/Dockerfile b/src/Api/Dockerfile index ef35ddac39..6547ec48d8 100644 --- a/src/Api/Dockerfile +++ b/src/Api/Dockerfile @@ -19,8 +19,7 @@ done # Custom -ARG source WORKDIR /app EXPOSE 80 -COPY ${source:-obj/Docker/publish} . +COPY obj/Docker/publish . ENTRYPOINT ["dotnet", "Api.dll"] diff --git a/src/Api/build.ps1 b/src/Api/build.ps1 new file mode 100644 index 0000000000..20bb292fb6 --- /dev/null +++ b/src/Api/build.ps1 @@ -0,0 +1,11 @@ +$dir = Split-Path -Parent $MyInvocation.MyCommand.Path + +echo "`n# Building API" + +echo "`nBuilding app" +echo ".NET Core version $(dotnet --version)" +dotnet publish $dir\Api.csproj -f netcoreapp2.0 -c "Release" -o $dir\obj\Docker\publish + +echo "`nBuilding docker image" +docker --version +docker build -t bitwarden/api $dir\. diff --git a/src/Api/build.sh b/src/Api/build.sh new file mode 100644 index 0000000000..473ed87e3c --- /dev/null +++ b/src/Api/build.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e + +DIR="$(dirname $(readlink -f $0))" + +echo -e "\n# Building API" + +echo -e "\nBuilding app" +echo -e ".NET Core version $(dotnet --version)" +dotnet publish $DIR/Api.csproj -f netcoreapp2.0 -c "Release" -o $DIR/obj/Docker/publish + +echo -e "\nBuilding docker image" +docker --version +docker build -t bitwarden/api $DIR/. diff --git a/src/Core/GlobalSettings.cs b/src/Core/GlobalSettings.cs index 22fc0374b4..c4be85ab22 100644 --- a/src/Core/GlobalSettings.cs +++ b/src/Core/GlobalSettings.cs @@ -61,6 +61,7 @@ public class IdentityServerSettings { public string CertificateThumbprint { get; set; } + public string CertificatePassword { get; set; } } public class DataProtectionSettings diff --git a/src/Core/Utilities/CoreHelpers.cs b/src/Core/Utilities/CoreHelpers.cs index 87784fe73d..206c8d9ed7 100644 --- a/src/Core/Utilities/CoreHelpers.cs +++ b/src/Core/Utilities/CoreHelpers.cs @@ -98,7 +98,7 @@ namespace Bit.Core.Utilities { // Clean possible garbage characters from thumbprint copy/paste // ref http://stackoverflow.com/questions/8448147/problems-with-x509store-certificates-find-findbythumbprint - thumbprint = Regex.Replace(thumbprint, @"[^\da-zA-z]", string.Empty).ToUpper(); + thumbprint = Regex.Replace(thumbprint, @"[^\da-fA-F]", string.Empty).ToUpper(); X509Certificate2 cert = null; var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); @@ -113,6 +113,11 @@ namespace Bit.Core.Utilities return cert; } + public static X509Certificate2 GetCertificate(string file, string password) + { + return new X509Certificate2(file, password); + } + public static long ToEpocMilliseconds(DateTime date) { return (long)Math.Round((date - _epoc).TotalMilliseconds, 0); diff --git a/src/Core/Utilities/ServiceCollectionExtensions.cs b/src/Core/Utilities/ServiceCollectionExtensions.cs index ce3573f062..62f57a8cca 100644 --- a/src/Core/Utilities/ServiceCollectionExtensions.cs +++ b/src/Core/Utilities/ServiceCollectionExtensions.cs @@ -144,6 +144,13 @@ namespace Bit.Core.Utilities { identityServerBuilder.AddTemporarySigningCredential(); } + else if(!string.IsNullOrWhiteSpace(globalSettings.IdentityServer.CertificatePassword) && + System.IO.File.Exists("identity.pfx")) + { + var identityServerCert = CoreHelpers.GetCertificate("identity.pfx", + globalSettings.IdentityServer.CertificatePassword); + identityServerBuilder.AddSigningCredential(identityServerCert); + } else { var identityServerCert = CoreHelpers.GetCertificate(globalSettings.IdentityServer.CertificateThumbprint); @@ -161,7 +168,7 @@ namespace Bit.Core.Utilities this IServiceCollection services, IHostingEnvironment env, GlobalSettings globalSettings) { #if NET461 - if(!env.IsDevelopment()) + if(!env.IsDevelopment() && !globalSettings.SelfHosted) { var dataProtectionCert = CoreHelpers.GetCertificate(globalSettings.DataProtection.CertificateThumbprint); var storageAccount = CloudStorageAccount.Parse(globalSettings.Storage.ConnectionString); diff --git a/src/Identity/.dockerignore b/src/Identity/.dockerignore index d8f8175f6c..7e37ce5d99 100644 --- a/src/Identity/.dockerignore +++ b/src/Identity/.dockerignore @@ -1,3 +1,4 @@ * !obj/Docker/publish/* !obj/Docker/empty/ +!entrypoint.sh diff --git a/src/Identity/Dockerfile b/src/Identity/Dockerfile index e87caa5ee3..1dacbf32ab 100644 --- a/src/Identity/Dockerfile +++ b/src/Identity/Dockerfile @@ -19,8 +19,10 @@ done # Custom -ARG source WORKDIR /app EXPOSE 80 -COPY ${source:-obj/Docker/publish} . -ENTRYPOINT ["dotnet", "Identity.dll"] +COPY obj/Docker/publish . + +COPY entrypoint.sh / +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] diff --git a/src/Identity/build.ps1 b/src/Identity/build.ps1 new file mode 100644 index 0000000000..aca2593ae9 --- /dev/null +++ b/src/Identity/build.ps1 @@ -0,0 +1,11 @@ +$dir = Split-Path -Parent $MyInvocation.MyCommand.Path + +echo "`n# Building Identity" + +echo "`nBuilding app" +echo ".NET Core version $(dotnet --version)" +dotnet publish $dir\Identity.csproj -f netcoreapp2.0 -c "Release" -o $dir\obj\Docker\publish + +echo "`nBuilding docker image" +docker --version +docker build -t bitwarden/identity $dir\. diff --git a/src/Identity/build.sh b/src/Identity/build.sh new file mode 100644 index 0000000000..625a63d0b8 --- /dev/null +++ b/src/Identity/build.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e + +DIR="$(dirname $(readlink -f $0))" + +echo -e "\n# Building Identity" + +echo -e "\nBuilding app" +echo -e ".NET Core version $(dotnet --version)" +dotnet publish $DIR/Identity.csproj -f netcoreapp2.0 -c "Release" -o $DIR/obj/Docker/publish + +echo -e "\nBuilding docker image" +docker --version +docker build -t bitwarden/identity $DIR/. diff --git a/src/Identity/entrypoint.sh b/src/Identity/entrypoint.sh new file mode 100644 index 0000000000..8b1f828c09 --- /dev/null +++ b/src/Identity/entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +cp /etc/core/identity.pfx /app/identity.pfx + +dotnet /app/Identity.dll