├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── bootstrap
├── Install-DCV.ps1
├── Install-DCVandSMAgent.ps1
├── dcv-gateway-installer.sh
├── dcv-session-manager-installer.sh
└── linux-config-sessionmgr-agent.sh
├── cdk
├── README.md
├── dcv-access-console
│ ├── README.md
│ ├── app.py
│ ├── cdk.json
│ ├── config.json
│ ├── documentation
│ │ └── images
│ │ │ └── SolutionArchitecture.png
│ ├── requirements.txt
│ ├── scripts
│ │ └── access-console-user-data.sh
│ └── stacks
│ │ └── dcv_ac_infra
│ │ └── dcv_ac_infra.py
├── dcv-gw-sm-with-pipelines
│ ├── README.md
│ ├── app.py
│ ├── cdk.json
│ ├── components
│ │ ├── build-dcv-connection-gwy.yaml
│ │ └── build-dcv-session-mgr.yaml
│ ├── config.json
│ ├── documentation
│ │ └── images
│ │ │ ├── EC2ImageBuilderRunPipeline.jpg
│ │ │ └── SolutionArchitecture.PNG
│ ├── requirements.txt
│ ├── scripts
│ │ ├── connection-gwy-user-data.sh
│ │ └── session-mgr-user-data.sh
│ └── stacks
│ │ ├── dcv_ami
│ │ ├── __init__.py
│ │ └── dcv_ami.py
│ │ └── dcv_infra
│ │ ├── __init__.py
│ │ └── dcv_infra.py
└── dcv-gw-sm-without-pipelines
│ ├── README.md
│ ├── app.py
│ ├── cdk.json
│ ├── config.json
│ ├── documentation
│ └── images
│ │ └── SolutionArchitecture.png
│ ├── requirements.txt
│ ├── scripts
│ ├── connection-gwy-user-data.sh
│ └── session-mgr-user-data.sh
│ └── stacks
│ └── dcv_infra
│ ├── __init__.py
│ └── dcv_infra.py
├── session-resolver
└── resolver.py
└── usage-reporting
├── Build-DCVUsageReports.ps1
└── Build-WSPUsageReports.ps1
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
4 | documentation, we greatly value feedback and contributions from our community.
5 |
6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
7 | information to effectively respond to your bug report or contribution.
8 |
9 |
10 | ## Reporting Bugs/Feature Requests
11 |
12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features.
13 |
14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already
15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
16 |
17 | * A reproducible test case or series of steps
18 | * The version of our code being used
19 | * Any modifications you've made relevant to the bug
20 | * Anything unusual about your environment or deployment
21 |
22 |
23 | ## Contributing via Pull Requests
24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
25 |
26 | 1. You are working against the latest source on the *main* branch.
27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
29 |
30 | To send us a pull request, please:
31 |
32 | 1. Fork the repository.
33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
34 | 3. Ensure local tests pass.
35 | 4. Commit to your fork using clear commit messages.
36 | 5. Send us a pull request, answering any default questions in the pull request interface.
37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
38 |
39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
41 |
42 |
43 | ## Finding contributions to work on
44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start.
45 |
46 |
47 | ## Code of Conduct
48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
50 | opensource-codeofconduct@amazon.com with any additional questions or comments.
51 |
52 |
53 | ## Security issue notifications
54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
55 |
56 |
57 | ## Licensing
58 |
59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
60 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT No Attribution
2 |
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Amazon DCV Samples
2 |
3 | Welcome to the DCV Samples repository within [AWS Samples](https://github.com/aws-samples). This repository will be used to host samples for Amazon DCV integrated workloads. These workloads include managed services that leverage DCV, such as [Amazon WorkSpaces](https://aws.amazon.com/workspaces/all-inclusive/) that stream with [DCV](https://docs.aws.amazon.com/workspaces/latest/adminguide/amazon-workspaces-protocols.html) (previously known as [WSP](https://aws.amazon.com/about-aws/whats-new/2024/10/nice-dcv-amazon-dcv-20240-ubuntu-2404/)).
4 |
5 | ## Glossary
6 | - [Bootstrap](./bootstrap/)
7 | - [AWS Cloud Development Kit Examples](./cdk/)
8 | - [Session Resolver](./session-resolver/)
9 | - [DCV Usage Reports](./usage-reporting/)
10 |
11 | ## Overview
12 |
13 | ### Bootstrap
14 | The provided script `dcv-gateway-installer.sh` bootstraps the installation and configuration of the DCV Connection Gateway component. This can be injected with [Amazon EC2 user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) or by running the script locally with `sudo`. To read more about the DCV Connection Gateway, see the [DCV Connection Gateway Administrator Guide](https://docs.aws.amazon.com/dcv/latest/gw-admin/what-is-gw.html).
15 |
16 | The provided script `dcv-session-manager-installer.sh` bootstraps the installation and configuration of the DCV Session Manager component. This can be injected with [Amazon EC2 user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) or by running the script locally with `sudo`. To read more about DCV Session Manager, see the [DCV Session Manager Administrator Guide](https://docs.aws.amazon.com/dcv/latest/sm-admin/what-is-sm.html).
17 |
18 | The provided script `Install-DCVandSMAgent.ps1` bootstraps the installation and configuration of DCV server and DCV Session Manager agent. This can be injected with [Amazon EC2 user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) or by running the script locally within an Administrator PowerShell terminal. Updating the `SESSION-MGR-PRIVATE-DNS` placeholder with the private DNS of DCV Session Manager allows the script to configure the host correctly.
19 |
20 | The provided script `Install-DCV.ps1` bootstraps the installation and configuration of only DCV server. This can be invoked by injecting with [Amazon EC2 user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) or by running the script locally within an Administrator PowerShell terminal. Optionally parameters are commented out to [configure automatic session creations](https://docs.aws.amazon.com/dcv/latest/adminguide/managing-sessions-start.html#managing-sessions-start-auto).
21 |
22 | The provided script `linux-config-sessionmgr-agent.sh` bootstraps the configuration of DCV server and DCV Session Manager agent. This can be injected with [Amazon EC2 user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) or by running the script locally with `sudo`. Updating the `SESSION-MGR-PRIVATE-DNS` placeholder with the private DNS of DCV Session Manager allows the script to configure the host correctly. Note, this script will only work on a host that already has DCV server and DCV Session Manager agent installed. It is intended to be used with the Linux-based [AWS Marketplace DCV AMIs](https://aws.amazon.com/marketplace/seller-profile?id=74eff437-1315-4130-8b04-27da3fa01de1).
23 |
24 |
25 | ### CDK
26 | This folder contains several [AWS Cloud Development Kit](https://aws.amazon.com/cdk/) (AWS CDK) examples for deploying DCV workloads as IaaC. For an overview of the current CDK examples, see the [README](/cdk/README.md) in the cdk folder.
27 |
28 | **Current CDK Examples**
29 | - Deploy a DCV Session Manager and DCV Connection Gateway environment
30 | - Deploy a DCV Session Manager and DCV Connection Gateway environment with EC2 Image Builder pipelines for both components
31 | - Deploy DCV Access Console
32 |
33 | ### Session Resolver
34 | The provided script provides logic to run in a AWS Lambda function to resolver DCV sessions streaming through a DCV Connection Gateway. To learn more, see the [Build a serverless session resolver for your Amazon DCV Connection Gateway](https://aws.amazon.com/blogs/desktop-and-application-streaming/build-a-serverless-session-resolver-for-your-nice-dcv-connection-gateway/) AWS blog post.
35 |
36 | ### DCV Usage Reports
37 | The provided scripts to generate DCV usage reports on Windows illustrate how to use DCV calls to find when a user starts and ends their session. This allows administrators to generate granular usage reports that can be further modified to include additional information. For a walkthrough of how to implement these reports on a DCV Amazon WorkSpace, see this [blog post](https://aws.amazon.com/blogs/desktop-and-application-streaming/generate-custom-usage-reports-for-amazon-workspaces/). Note, for WorkSpaces using DCV, utilize the WSP PowerShell script.
38 |
39 | ## Security
40 |
41 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
42 |
43 | ## License
44 |
45 | This library is licensed under the MIT-0 License. See the LICENSE file.
46 |
--------------------------------------------------------------------------------
/bootstrap/Install-DCV.ps1:
--------------------------------------------------------------------------------
1 |
2 | <#
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | software and associated documentation files (the "Software"), to deal in the Software
7 | without restriction, including without limitation the rights to use, copy, modify,
8 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 | #>
18 | $token = Invoke-RestMethod -Headers @{'X-aws-ec2-metadata-token-ttl-seconds' = '21600'} -Method PUT -Uri http://169.254.169.254/latest/api/token
19 | $instanceType = Invoke-RestMethod -Headers @{'X-aws-ec2-metadata-token' = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/instance-type
20 | $OSVersion = ((Get-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName) -replace "[^0-9]" , ''
21 | if(($OSVersion -eq "2016") -and (($InstanceType[0] -ne 'g') -or ($InstanceType[0] -ne 'p'))){
22 | $VirtualDisplayDriverRequired = $true
23 | }
24 | $token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
25 | $instanceType = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/instance-type
26 | # Check and install Visual C++ prerequisite
27 | $InstalledSoftware = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*) | Where-Object {$_.DisplayName -like "Microsoft Visual C++ 2022*"}
28 | if($InstalledSoftware.count -eq 0){
29 | Start-Job -Name VcWebReq -ScriptBlock { Invoke-WebRequest -uri https://aka.ms/vs/17/release/vc_redist.x64.exe -OutFile C:\Windows\Temp\vc_redist_64.exe }
30 | Wait-Job -Name VcWebReq
31 | Invoke-Command -ScriptBlock { . C:\Windows\Temp\vc_redist_64.exe /install /passive /norestart }
32 | }
33 | # Download Package(s)
34 | if($VirtualDisplayDriverRequired){
35 | Start-Job -Name WebReq -ScriptBlock { Invoke-WebRequest -uri https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-virtual-display-x64-Release.msi -OutFile C:\Windows\Temp\DCVDisplayDriver.msi ; Invoke-WebRequest -uri https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-server-x64-Release.msi -OutFile C:\Windows\Temp\DCVServer.msi }
36 | }else{
37 | Start-Job -Name WebReq -ScriptBlock { Invoke-WebRequest -uri https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-server-x64-Release.msi -OutFile C:\Windows\Temp\DCVServer.msi }
38 | }
39 | Wait-Job -Name WebReq
40 | # Install Package(s)
41 | if($VirtualDisplayDriverRequired){
42 | Invoke-Command -ScriptBlock {Start-Process "msiexec.exe" -ArgumentList "/I C:\Windows\Temp\DCVDisplayDriver.msi /quiet /norestart" -Wait}
43 | }
44 | Invoke-Command -ScriptBlock {Start-Process "msiexec.exe" -ArgumentList "/I C:\Windows\Temp\DCVServer.msi ADDLOCAL=ALL /quiet /norestart /l*v dcv_install_msi.log " -Wait}
45 | while (-not(Get-Service dcvserver -ErrorAction SilentlyContinue)) { Start-Sleep -Milliseconds 250 }
46 |
47 | # Automatic DCV Session Creation
48 | # https://docs.aws.amazon.com/dcv/latest/adminguide/managing-sessions-start.html#managing-sessions-start-auto
49 | #$dcvPath = "Microsoft.PowerShell.Core\Registry::\HKEY_USERS\S-1-5-18\Software\GSettings\com\nicesoftware\dcv"
50 | #New-ItemProperty -Path "$dcvPath\session-management" -Name create-session -PropertyType DWORD -Value 1 -force
51 | #New-ItemProperty -Path "$dcvPath\session-management\automatic-console-session" -Name owner -Value "USERNAME" -force
52 | #Restart-Service dcvserver
53 |
--------------------------------------------------------------------------------
/bootstrap/Install-DCVandSMAgent.ps1:
--------------------------------------------------------------------------------
1 |
2 | <#
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | software and associated documentation files (the "Software"), to deal in the Software
7 | without restriction, including without limitation the rights to use, copy, modify,
8 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 | #>
18 | $SessMgrDNS = "SESSION-MGR-PRIVATE-DNS"
19 | $BrokerAgentConnectionPort = "8445"
20 | $token = Invoke-RestMethod -Headers @{'X-aws-ec2-metadata-token-ttl-seconds' = '21600'} -Method PUT -Uri http://169.254.169.254/latest/api/token
21 | $instanceType = Invoke-RestMethod -Headers @{'X-aws-ec2-metadata-token' = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/instance-type
22 | $OSVersion = ((Get-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName) -replace "[^0-9]" , ''
23 | if(($OSVersion -eq "2016") -and (($InstanceType[0] -ne 'g') -or ($InstanceType[0] -ne 'p'))){
24 | $VirtualDisplayDriverRequired = $true
25 | }
26 | $token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
27 | $instanceType = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/instance-type
28 | # Check and install Visual C++ prerequisite
29 | $InstalledSoftware = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*) | Where-Object {$_.DisplayName -like "Microsoft Visual C++ 2022*"}
30 | if($InstalledSoftware.count -eq 0){
31 | Start-Job -Name VcWebReq -ScriptBlock { Invoke-WebRequest -uri https://aka.ms/vs/17/release/vc_redist.x64.exe -OutFile C:\Windows\Temp\vc_redist_64.exe }
32 | Wait-Job -Name VcWebReq
33 | Invoke-Command -ScriptBlock { . C:\Windows\Temp\vc_redist_64.exe /install /passive /norestart }
34 | }
35 | # Download Package(s)
36 | if($VirtualDisplayDriverRequired){
37 | Start-Job -Name WebReq -ScriptBlock { Invoke-WebRequest -uri https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-virtual-display-x64-Release.msi -OutFile C:\Windows\Temp\DCVDisplayDriver.msi ; Invoke-WebRequest -uri https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-server-x64-Release.msi -OutFile C:\Windows\Temp\DCVServer.msi }
38 | }else{
39 | Start-Job -Name WebReq -ScriptBlock { Invoke-WebRequest -uri https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-server-x64-Release.msi -OutFile C:\Windows\Temp\DCVServer.msi }
40 | }
41 | Wait-Job -Name WebReq
42 | # Install Package(s)
43 | if($VirtualDisplayDriverRequired){
44 | Invoke-Command -ScriptBlock {Start-Process "msiexec.exe" -ArgumentList "/I C:\Windows\Temp\DCVDisplayDriver.msi /quiet /norestart" -Wait}
45 | }
46 | Invoke-Command -ScriptBlock {Start-Process "msiexec.exe" -ArgumentList "/I C:\Windows\Temp\DCVServer.msi ADDLOCAL=ALL /quiet /norestart /l*v dcv_install_msi.log " -Wait}
47 | while (-not(Get-Service dcvserver -ErrorAction SilentlyContinue)) { Start-Sleep -Milliseconds 250 }
48 | $dcvPath = "Microsoft.PowerShell.Core\Registry::\HKEY_USERS\S-1-5-18\Software\GSettings\com\nicesoftware\dcv"
49 | Set-ItemProperty -Path "$dcvPath\session-management" -Name create-session -Value 0 -force
50 | New-ItemProperty -Path "$dcvPath\security" -Name "auth-token-verifier" -Value "https://$SessMgrDNS`:$BrokerAgentConnectionPort/agent/validate-authentication-token" -Force
51 | New-ItemProperty -Path "$dcvPath\security" -Name no-tls-strict -PropertyType DWORD -Value 1 -force
52 | Stop-Service dcvserver
53 |
54 | Start-Job -Name SMWebReq -ScriptBlock { Invoke-WebRequest -uri https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-session-manager-agent-x64-Release.msi -OutFile C:\Windows\Temp\DCVSMAgent.msi }
55 | Wait-Job -Name SMWebReq
56 | Invoke-Command -ScriptBlock {Start-Process "msiexec.exe" -ArgumentList "/I C:\Windows\Temp\DCVSMAgent.msi /quiet /norestart " -Wait}
57 | while (-not(Get-Service DcvSessionManagerAgentService -ErrorAction SilentlyContinue)) { Start-Sleep -Milliseconds 250 }
58 | Stop-Service DcvSessionManagerAgentService
59 |
60 | # SET AGENT.CONF
61 | $AgentConfContent = "version = '0.1'
62 | [agent]
63 | broker_host = '$SessMgrDNS'
64 | broker_port = $BrokerAgentConnectionPort
65 | tls_strict = false
66 | broker_update_interval = 15
67 | [log]
68 | level = 'debug'
69 | rotation = 'daily'
70 | "
71 | $AgentConfFolder = "C:\Program Files\NICE\DCVSessionManagerAgent\conf"
72 | New-Item -Path $AgentConfFolder -Name "agent.conf" -ItemType File -Force -Value "$AgentConfContent"
73 |
74 | Set-Service -Name DcvSessionManagerAgentService -StartupType Automatic
75 | Start-Service dcvserver
76 | Start-Service DcvSessionManagerAgentService
77 |
--------------------------------------------------------------------------------
/bootstrap/dcv-gateway-installer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this
5 | # software and associated documentation files (the "Software"), to deal in the Software
6 | # without restriction, including without limitation the rights to use, copy, modify,
7 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | # NICE DCV Connection Gateway Installer Script
18 |
19 | set -eE
20 |
21 | # Retrieve System Info
22 | read -r system version <<<$(echo $(cat /etc/os-release | grep "^ID=\|^VERSION_ID=" | sort | cut -d"=" -f2 | tr -d "\"" | tr '[:upper:]' '[:lower:]'))
23 | major_version="${version%.*}"
24 | arch="$(arch)"
25 | CLOUDFRONT_PREFIX="https://d1uj6qtbmh3dt5.cloudfront.net"
26 | TMP_DIR="$(mktemp -d /tmp/XXXXXX)"
27 | trap 'rm -rf -- "$TMP_DIR"' ERR
28 |
29 | case $system in
30 | amzn )
31 | if [ "$major_version" = 2 ]; then
32 | package_type="el7"
33 | package_manager="yum"
34 | package_extension="rpm"
35 | fi
36 | ;;
37 | centos|rhel )
38 | if [[ "$major_version" =~ ^(7|8|9) ]]; then
39 | package_type="el$major_version"
40 | if [[ "$major_version" =~ ^(8|9) ]]; then
41 | package_manager="dnf"
42 | else
43 | package_manager="yum"
44 | fi
45 | package_extension="rpm"
46 | fi
47 | ;;
48 | ubuntu )
49 | if [ "$major_version" = 22 ] || [ "$major_version" = 20 ]; then
50 | package_type="ubuntu$(echo $version | tr -d '.')"
51 | package_manager="apt"
52 | package_extension="deb"
53 | fi
54 | ;;
55 | * )
56 | echo "Error: system '$system' is not supported"
57 | exit 1
58 | ;;
59 | esac
60 |
61 | if [ -z "$package_type" ]; then
62 | echo "Error: system '$system' with version '$version' is not supported for arch '$arch'"
63 | exit 1
64 | fi
65 |
66 | # Download Packages
67 | if [ "$package_manager" = apt ]; then
68 | curl -o "$TMP_DIR/NICE-GPG-KEY" "$CLOUDFRONT_PREFIX/NICE-GPG-KEY"
69 | gpg --import "$TMP_DIR/NICE-GPG-KEY"
70 | if [ $arch != "x86_64" ]; then
71 | deb_arch="arm64"
72 | curl -o "$TMP_DIR/nice-dcv-server.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-ubuntu2204-aarch64.tgz"
73 | else
74 | deb_arch="amd64"
75 | curl -o "$TMP_DIR/nice-dcv-server.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-$package_type-$arch.tgz"
76 | fi
77 | curl -o "$TMP_DIR/nice-dcv-connection-gateway.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-connection-gateway_$deb_arch.$package_type.$package_extension"
78 | else
79 | rpm --import "$CLOUDFRONT_PREFIX"/NICE-GPG-KEY
80 | curl -o "$TMP_DIR/nice-dcv-connection-gateway.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-connection-gateway-$package_type.$arch.$package_extension"
81 | curl -o "$TMP_DIR/nice-dcv-server.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-$package_type-$arch.tgz"
82 | fi
83 |
84 | # Install Packages
85 | tar -xvzf "$TMP_DIR/nice-dcv-server.tgz" -C "$TMP_DIR"
86 | for package_pattern in "nice-dcv-web-viewer*" "nice-dcv-connection-gateway.$package_extension"; do
87 | package_full_path=$(find "$TMP_DIR" -name "$package_pattern")
88 | "$package_manager" install -y "$package_full_path"
89 | done
90 |
91 | # Configure Gateway
92 | ## Enables Web Access through the Gateway
93 | sed -i --expression 's|url = "https://localhost:8080"|local-resources-path = "/usr/share/dcv/www"|' /etc/dcv-connection-gateway/dcv-connection-gateway.conf
94 | ## Uncomment the line below to add your Session Resolver and replace the placeholder
95 | #sed -i --expression 's|url = "https://localhost:8081"|url = "https://RESOLVER-URL"|' /etc/dcv-connection-gateway/dcv-connection-gateway.conf
96 |
97 | # Enable and start Gateway
98 | systemctl enable dcv-connection-gateway
99 | systemctl start dcv-connection-gateway
100 |
101 | # Clean Up
102 | rm -rf "$TMP_DIR"
103 |
--------------------------------------------------------------------------------
/bootstrap/dcv-session-manager-installer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this
5 | # software and associated documentation files (the "Software"), to deal in the Software
6 | # without restriction, including without limitation the rights to use, copy, modify,
7 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | # NICE DCV Session Manager Installer Script
18 |
19 | set -eE
20 |
21 | # Retrieve System Info
22 | read -r system version <<<$(echo $(cat /etc/os-release | grep "^ID=\|^VERSION_ID=" | sort | cut -d"=" -f2 | tr -d "\"" | tr '[:upper:]' '[:lower:]'))
23 | major_version="${version%.*}"
24 | CLOUDFRONT_PREFIX="https://d1uj6qtbmh3dt5.cloudfront.net"
25 | TMP_DIR="$(mktemp -d /tmp/XXXXXX)"
26 | trap 'rm -rf -- "$TMP_DIR"' ERR
27 |
28 | case $system in
29 | amzn )
30 | if [ "$major_version" = 2 ]; then
31 | package_type="el7"
32 | package_manager="yum"
33 | package_extension="rpm"
34 | fi
35 | ;;
36 | centos|rhel )
37 | if [[ "$major_version" =~ ^(7|8|9) ]]; then
38 | package_type="el$major_version"
39 | if [[ "$major_version" =~ ^(8|9) ]]; then
40 | package_manager="dnf"
41 | else
42 | package_manager="yum"
43 | fi
44 | package_extension="rpm"
45 | fi
46 | ;;
47 | ubuntu )
48 | if [ "$major_version" = 22 ] || [ "$major_version" = 20 ]; then
49 | package_type="ubuntu$(echo $version | tr -d '.')"
50 | package_manager="apt"
51 | package_extension="deb"
52 | fi
53 | ;;
54 | * )
55 | echo "Error: system '$system' is not supported"
56 | exit 1
57 | ;;
58 | esac
59 |
60 |
61 | if [ -z "$package_type" ]; then
62 | echo "Error: system '$system' with version '$version' is not supported"
63 | exit 1
64 | fi
65 |
66 | # Download Packages
67 | if [ "$package_manager" = apt ]; then
68 | curl -o "$TMP_DIR/NICE-GPG-KEY" "$CLOUDFRONT_PREFIX/NICE-GPG-KEY"
69 | gpg --import "$TMP_DIR/NICE-GPG-KEY"
70 | curl -o "$TMP_DIR/nice-dcv-session-manager-broker.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-session-manager-broker_all.$package_type.$package_extension"
71 | else
72 | rpm --import "$CLOUDFRONT_PREFIX"/NICE-GPG-KEY
73 | curl -o "$TMP_DIR/nice-dcv-session-manager-broker.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-session-manager-broker-$package_type.noarch.$package_extension"
74 | fi
75 |
76 | # Install Packages
77 | for package_pattern in "nice-dcv-session-manager-broker.$package_extension"; do
78 | package_full_path=$(find "$TMP_DIR" -name "$package_pattern")
79 | "$package_manager" install -y "$package_full_path"
80 | done
81 |
82 | # Enable and start DCV Session Manager service
83 | systemctl start dcv-session-manager-broker
84 | systemctl enable dcv-session-manager-broker
85 |
86 | # Configure DCV Session Manager
87 | CONFIG_PATH="/etc/dcv-session-manager-broker/session-manager-broker.properties"
88 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
89 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
90 | ## Enable the gateway in config
91 | sed -i '/^enable-gateway/s/=.*$/= true/' "$CONFIG_PATH"
92 | ## Uncomment the broker connector host and port in config
93 | sed -i '/gateway-to-broker-connector-https-port/s/^#\s//g' "$CONFIG_PATH"
94 | sed -i '/gateway-to-broker-connector-bind-host/s/^#\s//g' "$CONFIG_PATH"
95 |
96 | ## (Optional) Uncomment the following entries to enable the broker to persist on Amazon DynamoDB in config
97 | #sed -i '/^enable-persistence/s/=.*$/= true/' "$CONFIG_PATH"
98 | #sed -i '/persistence-db/s/^#\s//g' "$CONFIG_PATH"
99 | #sed -i '/dynamodb-region/s/^#\s//g' "$CONFIG_PATH"
100 | #sed -i '/dynamodb-table-rcu/s/^#\s//g' "$CONFIG_PATH"
101 | #sed -i '/dynamodb-table-wcu/s/^#\s//g' "$CONFIG_PATH"
102 | #sed -i '/dynamodb-table-name-prefix/s/^#\s//g' "$CONFIG_PATH"
103 | #sed -i "/^dynamodb-region/s/=.*$/= $REGION/" "$CONFIG_PATH"
104 |
105 | # Restart the broker service
106 | systemctl restart dcv-session-manager-broker.service
107 |
108 | # Clean Up
109 | rm -rf "$TMP_DIR"
--------------------------------------------------------------------------------
/bootstrap/linux-config-sessionmgr-agent.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this
5 | # software and associated documentation files (the "Software"), to deal in the Software
6 | # without restriction, including without limitation the rights to use, copy, modify,
7 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | BROKER_PRIVATE_DNS="SESSION-MGR-PRIVATE-DNS"
18 | sed -i --expression "s|#auth-token-verifier=\"https://127.0.0.1:8444\"|auth-token-verifier=\"https://$BROKER_PRIVATE_DNS:8445/agent/validate-authentication-token\"|" /etc/dcv/dcv.conf
19 | sed -i "/\[security\]/a administrators=[\"dcvsmagent\"]\nno-tls-strict=true" /etc/dcv/dcv.conf
20 | sed -i --expression "s|broker_host = ''|broker_host = \"$BROKER_PRIVATE_DNS\"|" /etc/dcv-session-manager-agent/agent.conf
21 | sed -i --expression 's|#tls_strict = false|tls_strict = false|' /etc/dcv-session-manager-agent/agent.conf
22 | systemctl enable dcv-session-manager-agent.service
23 | systemctl start dcv-session-manager-agent
24 | systemctl restart dcvserver
--------------------------------------------------------------------------------
/cdk/README.md:
--------------------------------------------------------------------------------
1 | # DCV CDK Samples
2 |
3 | This folder contains sample DCV deployments using the [AWS Cloud Development Kit](https://aws.amazon.com/cdk/) (AWS CDK). These samples are intended to be used so you quickly deploy a DCV environment. The code samples may be modified to meet you requirements.
4 |
5 | ## Glossary
6 | - [dcv-gw-sm-without-pipelines](./dcv-gw-sm-without-pipelines/README.md)
7 | - [dcv-gw-sm-with-pipelines](./dcv-gw-sm-with-pipelines/README.md)
8 | - [dcv-sm-access-console](./dcv-access-console/README.md)
9 |
10 | ## Overview
11 |
12 | ### dcv-gw-sm-without-pipelines
13 | This AWS CDK sample provisions the foundational infrastructure for a [DCV Connection Gateway](https://docs.aws.amazon.com/dcv/latest/gw-admin/what-is-gw.html) with [DCV Session Manager](https://docs.aws.amazon.com/dcv/latest/sm-admin/what-is-sm.html) environment. Both DCV Session Manager and DCV Connection Gateway are configured with bootstrap scripts so that can you utilize base AMIs. This deployment is intended to be deployed with Amazon Linux 2, but you can also deploy using other supported operating systems. For more information, see the associated [README](./dcv-gw-sm-without-pipelines/README.md).
14 |
15 | 
16 |
17 | ### dcv-gw-sm-with-pipelines
18 | This AWS CDK sample provisions the foundational infrastructure for a [DCV Connection Gateway](https://docs.aws.amazon.com/dcv/latest/gw-admin/what-is-gw.html) with [DCV Session Manager](https://docs.aws.amazon.com/dcv/latest/sm-admin/what-is-sm.html) environment. Both DCV Session Manager and DCV Connection Gateway have EC2 Image Builder pipelines to publish a configured AMI. This deployment is intended to be deployed with ARM-based Amazon Linux 2, but you can also deploy using other supported operating systems. For more information, see the associated [README](./dcv-gw-sm-with-pipelines/README.md).
19 |
20 | 
21 |
22 | ### dcv-access-console
23 | This AWS CDK sample provisions a single Amazon EC2 instance that hosts all of the [DCV Access Console](https://docs.aws.amazon.com/dcv/latest/access-console/what-is-access-console.html) components. This deployment depends on an existing DCV Session Manager environment. If you do not have an existing environment, you may deploy *dcv-gw-sm-without-pipelines* or *dcv-gw-sm-with-pipelines* before deploying *dcv-access-console*. This CDK is intended to be deployed with ARM-based Amazon Linux 2023, but you can also deploy using other supported operating systems. The usage of a DCV Connection Gateway is optional. The CDK also supports the DCV Access Console being deployed in a private subnet to be accessed internally. For more information, see the associated [README](./dcv-access-console/README.md).
24 |
25 | 
26 |
27 | ## Security
28 |
29 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
30 |
31 | ## License
32 |
33 | This library is licensed under the MIT-0 License. See the LICENSE file.
34 |
--------------------------------------------------------------------------------
/cdk/dcv-access-console/README.md:
--------------------------------------------------------------------------------
1 | # Amazon DCV Access Console Deployment
2 |
3 | Accelerate [Amazon DCV Access Console](https://docs.aws.amazon.com/dcv/latest/access-console/what-is-access-console.html) deployments with the AWS Cloud Development Kit (AWS CDK). This CDK will create a single Amazon Elastic Compute Cloud (Amazon EC2) instance to host all of the required DCV Access Console components.
4 |
5 | ## Overview
6 | The architecture diagram below depicts the resources that this solution will deploy into your account. This CDK will only deploy the DCV Access Console. An existing DCV Session Manager environment is required. The DCV Connection Gateway in the diagram is optional.
7 |
8 | 
9 |
10 | Figure 1: AWS CDK that will deploy and configure a DCV Access Console on a single instance in an existing DCV Session Manager environment.
11 |
12 | ## Prerequisites
13 | - An AWS account with full permissions on:
14 | - AWS Systems Manager Parameter Store
15 | - AWS Systems Manager Session Manager
16 | - Amazon Elastic Compute Cloud (Amazon EC2)
17 | - Amazon VPC
18 | - A system with the following installed:
19 | - AWS CLI
20 | - AWS CDK
21 | - Node.js
22 | - Python
23 | - Git
24 | - Basic understanding of:
25 | - AWS Cloud
26 | - DCV usage
27 | - Scripting languages (Python, Bash)
28 |
29 | # AWS VPC Infrastructure Creation with CDK
30 | This example creates:
31 | - A single EC2 instance hosting the DCV Access Console
32 | - Systems Manager Parameter Store parameters
33 | - IAM role for Access Console
34 | - Security Group for Access Console
35 |
36 | >Note: An SSH key-pair (.pem) is required to be registered in your AWS account and region. This key-pair name needs to be entered in the `config.json` file before deploying the infra stack in order to allow SSH access into the instance.
37 |
38 | ## Step 1: NPM
39 | The LTS version of [npm](https://www.npmjs.com/) is recommended. If npm is already on your system, upgrade npm to the latest version.
40 |
41 | ```bash
42 | npm install -g npm@latest
43 | ```
44 |
45 | ## Step 2: AWS CDK
46 |
47 | Ensure that the latest [aws-cdk](https://aws.amazon.com/cdk/) is installed.
48 |
49 | ```bash
50 | npm install -g aws-cdk
51 | ```
52 |
53 | Once installed, the following command confirms the installation was successful.
54 |
55 | ```bash
56 | cdk --version
57 | ```
58 |
59 | ## Step 3: AWS CLI
60 | Install [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
61 |
62 |
63 | ## Step 4: Git
64 | Install [Git](https://git-scm.com/)
65 |
66 | ## Step 5: Clone the repository
67 | Visit [clone a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) for instructions. Clone this repository locally.
68 |
69 | ## Step 6: Create a virtual environment
70 | Open up a command line terminal of your choice.
71 | ### Windows
72 | ```bash
73 | virtualenv --python dcv-env
74 | .\dcv-env\Scripts\activate
75 | ```
76 |
77 | ### macOS/Linux
78 | ```bash
79 | virtualenv --python dcv-env
80 | source dcv-env/bin/activate
81 | ```
82 |
83 | ## Step 7: Install Project Dependencies
84 | Change directory into the **cdk** folder of the cloned repository. Install project dependencies.
85 |
86 | ```bash
87 | pip install -r requirements.txt
88 | ```
89 |
90 | ## Step 8: Assume IAM role
91 | [Use an IAM role in the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html).
92 | > Note: To confirm your credentials are associated with the correct AWS account, you can run the following AWS CLI command -
93 |
94 | ```bash
95 | aws sts get-caller-identity
96 | ```
97 | (See [get-caller-identity](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/get-caller-identity.html) in the AWS CLI documentation).
98 |
99 | ## Step 9: CDK Bootstrap
100 | [Bootstrap your AWS CDK environment. ](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-bootstrap)
101 | Replace with your desired account number and region.
102 |
103 | ```bash
104 | cdk bootstrap 1234567890/us-east-1
105 | ```
106 |
107 | ## Step 10: Set AWS Account and Region for Infrastructure
108 | Set the AWS account id and region by specifying in `/config.json`
109 | ```bash
110 | {
111 | ...
112 | "accountId": "xxxxxxxxxxxx",
113 | "region": "xx-xxxx-x",
114 | ...
115 | }
116 | ```
117 |
118 | Ensure the region is set in your AWS credentials by running the following command by replacing `us-east-1` with your intended region:
119 |
120 | For Windows:
121 | ```bash
122 | set AWS_REGION=us-east-1
123 | ```
124 | For Mac/Linux:
125 | ```bash
126 | export AWS_REGION=us-east-1
127 | ```
128 |
129 | ## Step 11: Key Pairs for EC2
130 | Use your own Key Pair or [Create Key Pairs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-key-pairs.html) for accessing the EC2s.
131 |
132 | Use the Key Pair value for *sshKeypairName* in `/config.json`
133 |
134 | ```bash
135 | {
136 | "accountId": "xxxxxxxxxxxx",
137 | ...
138 | "sshKeypairName": "xxxxxxxxxxxxxxx",
139 | ...
140 | }
141 | ```
142 |
143 | ## Step 12: AWS Key Management Service (KMS)
144 | Choose to use the AWS provide default KMS or [Create Keys](href="https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html).
145 |
146 | Use the KMS value for kms_key_name in `/config.json`
147 |
148 | ```bash
149 | {
150 | "accountId": "xxxxxxxxxxxx",
151 | ...
152 | "kmsKeyName": "aws/ebs",
153 | ...
154 | }
155 | ```
156 |
157 | ## Step 13: Networking
158 | Provide the network details for where the DCV Access Console should be provisioned. This includes the VPC ID, Subnet ID, and Availability Zone (ie. us-east-1a).
159 |
160 | **Note:** If you provide a private subnet, it needs to have a route to a NAT Gateway to download components. Private deployments can only be accessed on the private network.
161 |
162 | ```json
163 | {
164 | ...
165 | "network" : {
166 | "vpcId": "vpc-xxxxxxxxxxxxxxxxx",
167 | "accessConsoleSubnetId": "subnet-xxxxxxxxxxxxxxxxx",
168 | "subnetAZ": "xx-xxxx-xx"
169 | }, ...
170 | }
171 | ```
172 |
173 |
174 | ## Step 14: Update the Access Console parameters
175 | This CDK is intended to deployed in an existing DCV Session Manager environment. Update the `config.json` parameters to align to your existing environment.
176 |
177 | ### amiId
178 | This CDK is intended to be deployed using the ARM-based Amazon Linux 2023 AMI. This can be found within the [AMI Catalog](https://console.aws.amazon.com/ec2/home?#AMICatalog:).
179 |
180 | If you would like to use a different [supported distribution for DCV Access Console](https://docs.aws.amazon.com/dcv/latest/access-console/requirements.html), ensure you meet the following AMI checklist.
181 |
182 | **AMI Checklist**
183 | - The provided AMI is based on a [supported distribution for DCV Access Console](https://docs.aws.amazon.com/dcv/latest/access-console/requirements.html).
184 | - Ensure your provided AMI is up to date and has the [AWS CLI](https://aws.amazon.com/cli/) installed.
185 | - The CDK assumes you are using ARM-based AMIs so you can benefit from [EC2 Graviton](https://aws.amazon.com/ec2/graviton/). If you would like to use an x86-based AMI, you may update the statically configured instance types in *dcv_ac_infra.py*.
186 | - To utilize AWS Systems Manager Session Manager for access, ensure [SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) is installed within your AMI.
187 |
188 | **Note:** If you plan to use Ubuntu, it is recommended you run the [installation wizard](https://docs.aws.amazon.com/dcv/latest/access-console/using-setup-wizard.html) manually. Modify *access-console-user-data.py* to align to the Ubuntu commented caveats (comment out wizard call and uncomment the TMP_DIR).
189 |
190 | ### sessionMgrDns
191 | This parameter is the private DNS name of your DCV Session Manager. This parameter configures the DCV Access Console to contact DCV Session Manager through the provided DNS name.
192 |
193 | ### DCV Session Manager credentials
194 | To interact with DCV Session Manager, the client needs to have registered credentials. If you do not have registered credentials for DCV Session Manager, see *Prerequisites* in the [DCV Access Console Administrator Guide](https://docs.aws.amazon.com/dcv/latest/access-console/prerequisites.html). These credentials are stored in SSM Parameter Store so the Access Console instance can retrieve them. Users with Identity Access Management permissions that permit access to the parameter will also be able to retrieve the credentials.
195 |
196 | - **smClientId** - Provide your registered Client ID.
197 | - **smClientPsw** - Provide your registered Client Password.
198 |
199 | ### adminUser
200 | This CDK configures the DCV Access Console to use *system-auth*, which redirects the credentials to the PAM module on the DCV Access Console host. On Amazon Linux 2023, the default created user is *ec2-user*. If you choose use this user for testing, connect to the DCV Access Console with SSM Session Manager and set a password for *ec2-user*. For example, `sudo passwd ec2-user`.
201 |
202 | ### gatewayDns (Optional)
203 | If your existing environment utilizes a [DCV Connection Gateway](https://docs.aws.amazon.com/dcv/latest/gw-admin/what-is-gw.html), provide the DNS name for the gateway in this parameter. If you front your gateways with a NLB, provide the DNS name of the NLB.
204 |
205 | **If you do not use a gateway, leave this parameter blank.**
206 |
207 |
208 | ### inboundAccess
209 | This parameter configures the inbound access on the DCV Access Console Security Group. By default, the connection is made on port 443. If you would like to isolate this to a specific IP range, update this parameter.
210 |
211 | **The default parameter allows 443 traffic from anywhere**
212 |
213 | Example config.json
214 |
215 | ```bash
216 | {
217 | ...
218 | "accessConsole" : {
219 | "amiId": "ami-xxxxxxxxxxxxxxxxx",
220 | "sessionMgrDns": "PRIVATE-BROKER-DNS",
221 | "smClientId": "ASIAIOSFODNN7EXAMPLE",
222 | "smClientPsw": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
223 | "adminUser": "ec2-user",
224 | "gatewayDns": "",
225 | "inboundAccess": "0.0.0.0/0"
226 | }
227 | }
228 | ```
229 |
230 | ## Step 15: Check Project with Synth
231 | Verify there are no errors with the cloned project with [cdk synth](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-synth) (synthesize).
232 | ```bash
233 | cdk synth --all
234 | ```
235 |
236 | ## Step 16: Deploy DCV Access Console stack
237 | ```bash
238 | cdk deploy
239 | ```
240 |
241 | ## Step 17: Testing your Configuration
242 | After your deployment is finished, the CDK the output the URL of your DCV Access Console. Once the underlying EC2 instance is passing health checks, you can access the DCV Access Console through this URL. For usage instructions, see *Getting started with the Amazon DCV Session Manager console* in the [DCV Access Console Administrator Guide](https://docs.aws.amazon.com/dcv/latest/access-console/getting-started.html)
243 |
244 | ## Cleanup your Environment
245 | To destroy all infrastructure contained in the CDK, run the following command:
246 | ```bash
247 | cdk destroy
248 | ```
249 |
250 | ## Troubleshooting DCV Access Console
251 | See the *Troubleshooting* section of the [DCV Access Console Administrator Guide](https://docs.aws.amazon.com/dcv/latest/access-console/troubleshooting.html).
252 |
253 | The bash bootstrap creates a log file located at `/var/log/dcv-access-console-install.log`. This bootstrap builds your configuration file (`onebox-config-input.json`) and passes it into the [DCV Access Console Setup Wizard](https://docs.aws.amazon.com/dcv/latest/access-console/using-setup-wizard.html). The installation is placed within a temporary directory, which can be found in the bootstrap log. The Setup Wizard created detailed installation logs within the `output` directory. If you find the installation failed on a step, you may run the installation again. This can be performed by connecting to the Access Console instance with AWS SSM Session Manager and running the following command from within the installation directory:
254 |
255 | `sudo python3 wizard.py --is-onebox --input-json onebox-config-input.json --force`
256 |
257 | ## CDK Feedback
258 | If you have issues or feedback, open an issue on the Github repository. Note, this CDK is licensed as MIT-0. As-is examples are not supported by AWS Support.
259 |
260 | ## Authors and acknowledgment
261 | [Andrew Morgan](https://github.com/morgnza)
262 |
263 | ## License
264 | MIT License
--------------------------------------------------------------------------------
/cdk/dcv-access-console/app.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | # this software and associated documentation files (the "Software"), to deal in
5 | # the Software without restriction, including without limitation the rights to
6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | # the Software, and to permit persons to whom the Software is furnished to do so.
8 | #
9 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import json
17 | import aws_cdk as cdk
18 | from stacks.dcv_ac_infra.dcv_ac_infra import DcvAccessConsole
19 |
20 | app = cdk.App()
21 |
22 | # Load the app configuration from the config.json file
23 | try:
24 | with open("config.json", "r") as config_file:
25 | config_data = json.load(config_file)
26 | except Exception as e:
27 | print(f"Could not read the app configuration file. {e}")
28 | raise e
29 |
30 |
31 | # Set CDK environment variables
32 | environment = cdk.Environment(account=config_data['accountId'], region=config_data['region'])
33 |
34 | # Create the DCV Infrastructure Stack for Session Manager and Connection Gateway
35 | DcvAccessConsole(app, "DcvAccessConsole",
36 | description='(uksb-1tupboc66) (tag:dcv-access-console)',
37 | config_data=config_data,
38 | env=environment)
39 |
40 | app.synth()
--------------------------------------------------------------------------------
/cdk/dcv-access-console/cdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": "python app.py",
3 | "watch": {
4 | "include": [
5 | "**"
6 | ],
7 | "exclude": [
8 | "README.md",
9 | "cdk*.json",
10 | "requirements*.txt",
11 | "**/__init__.py",
12 | "**/__pycache__"
13 | ]
14 | },
15 | "context": {
16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
17 | "@aws-cdk/core:checkSecretUsage": true,
18 | "@aws-cdk/core:target-partitions": [
19 | "aws",
20 | "aws-cn"
21 | ],
22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
25 | "@aws-cdk/aws-iam:minimizePolicies": true,
26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
31 | "@aws-cdk/core:enablePartitionLiterals": true,
32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
33 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true,
34 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
35 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
36 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
37 | "@aws-cdk/aws-route53-patters:useCertificate": true,
38 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false,
39 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
40 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
41 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
42 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
43 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
44 | "@aws-cdk/aws-redshift:columnId": true,
45 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
46 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
47 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
48 | "@aws-cdk/aws-kms:aliasNameRef": true,
49 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
50 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
51 | "@aws-cdk/aws-efs:denyAnonymousAccess": true,
52 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
53 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
54 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
55 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
56 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
57 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
58 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/cdk/dcv-access-console/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "comment": "NOTE: BEFORE DEPLOYING SESSION MANAGER AND CONNECTION GATEWAY STACK, UPDATE THE ACCOUNT ID AND REGION BELOW",
3 | "accountId": "xxxxxxxxxxxxx",
4 | "region": "xx-xxxx-x",
5 | "sshKeypairName": "",
6 | "kmsKeyName": "aws/ebs",
7 | "network" : {
8 | "vpcId": "vpc-xxxxxxxxxxxxxxxxx",
9 | "accessConsoleSubnetId": "subnet-xxxxxxxxxxxxxxxxx",
10 | "subnetAZ": "xx-xxxx-xx"
11 | },
12 | "accessConsole" : {
13 | "amiId": "",
14 | "sessionMgrDns": "https://PRIVATE-BROKER-DNS",
15 | "smClientId": "",
16 | "smClientPsw": "",
17 | "adminUser": "ec2-user",
18 | "gatewayDns": "",
19 | "inboundAccess": "0.0.0.0/0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/cdk/dcv-access-console/documentation/images/SolutionArchitecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/dcv-samples/62554cb1deb94b843a7faceb94ff774b94f73243/cdk/dcv-access-console/documentation/images/SolutionArchitecture.png
--------------------------------------------------------------------------------
/cdk/dcv-access-console/requirements.txt:
--------------------------------------------------------------------------------
1 | aws-cdk-lib>=2.141.0
2 | constructs>=10.0.0,<11.0.0
--------------------------------------------------------------------------------
/cdk/dcv-access-console/scripts/access-console-user-data.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | # this software and associated documentation files (the "Software"), to deal in
6 | # the Software without restriction, including without limitation the rights to
7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | # the Software, and to permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
12 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
14 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | LOG_PATH="/var/log/dcv-access-console-install.log"
18 | echo $(date -u) "*****START USER DATA SCRIPT*****" | tee -a "$LOG_PATH"
19 | TMP_DIR="$(mktemp -d /tmp/XXXXXX)"
20 | echo $(date -u) "Created temp directory: $TMP_DIR" | tee -a "$LOG_PATH"
21 |
22 | # Uncommet the following two lines if launching an Ubuntu based AMI
23 | #TMP_DIR="/etc/dcv-access-console-install"
24 | #mkdir "$TMP_DIR"
25 |
26 | # Retrieve System Info
27 | read -r system version <<<$(echo $(cat /etc/os-release | grep "^ID=\|^VERSION_ID=" | sort | cut -d"=" -f2 | tr -d "\"" | tr '[:upper:]' '[:lower:]'))
28 | major_version="${version%.*}"
29 | arch="$(arch)"
30 | CLOUDFRONT_PREFIX="https://d1uj6qtbmh3dt5.cloudfront.net"
31 |
32 | case $system in
33 | amzn )
34 | if [ "$major_version" = 2023 ]; then
35 | package_type="el9"
36 | package_manager="yum"
37 | package_extension="rpm"
38 | elif [ "$major_version" = 2 ]; then
39 | package_type="el7"
40 | package_manager="yum"
41 | package_extension="rpm"
42 | fi
43 | ;;
44 | centos|rhel|rocky )
45 | if [[ "$major_version" =~ ^(7|8|9) ]]; then
46 | package_type="el$major_version"
47 | if [[ "$major_version" =~ ^(8|9) ]]; then
48 | package_manager="dnf"
49 | else
50 | package_manager="yum"
51 | fi
52 | package_extension="rpm"
53 | fi
54 | ;;
55 | ubuntu )
56 | if [ "$major_version" = 22 ] || [ "$major_version" = 20 ]; then
57 | package_type="ubuntu$(echo $version | tr -d '.')"
58 | package_manager="apt"
59 | package_extension="deb"
60 | fi
61 | ;;
62 | * )
63 | echo $(date -u) "Error: system '$system' is not supported" | tee -a "$LOG_PATH"
64 | exit 1
65 | ;;
66 | esac
67 |
68 | if [ -z "$package_type" ]; then
69 | echo $(date -u) "Error: system '$system' with version '$version' is not supported for arch '$arch'" | tee -a "$LOG_PATH"
70 | exit 1
71 | fi
72 |
73 | echo $(date -u) "System Info detected:" | tee -a "$LOG_PATH"
74 | echo $(date -u) "OS Type: $package_type" | tee -a "$LOG_PATH"
75 | echo $(date -u) "Package Manager: $package_manager" | tee -a "$LOG_PATH"
76 |
77 | if ! command -v jq &> /dev/null
78 | then
79 | echo $(date -u) "jq dependency not found. Installing" | tee -a "$LOG_PATH"
80 | "$package_manager" install -y jq
81 | fi
82 |
83 | if ! command -v aws &> /dev/null
84 | then
85 | echo $(date -u) "awscli dependency not found. Installing" | tee -a "$LOG_PATH"
86 | "$package_manager" install -y awscli
87 | fi
88 |
89 | # Download Packages
90 | if [ "$package_manager" = apt ]; then
91 | curl -o "$TMP_DIR/NICE-GPG-KEY" "$CLOUDFRONT_PREFIX/NICE-GPG-KEY"
92 | gpg --import "$TMP_DIR/NICE-GPG-KEY"
93 | if [ $arch != "x86_64" ]; then
94 | curl -o "$TMP_DIR/nice-dcv-access-console.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-access-console-$package_type-aarch64.tgz"
95 | else
96 | curl -o "$TMP_DIR/nice-dcv-access-console.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-access-console-$package_type-x86_64.tgz"
97 | fi
98 | else
99 | rpm --import "$CLOUDFRONT_PREFIX"/NICE-GPG-KEY
100 | curl -o "$TMP_DIR/nice-dcv-access-console.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-access-console-$package_type-$arch.tgz"
101 | fi
102 |
103 | echo $(date -u) "DCV Access Console packages downloaded" | tee -a "$LOG_PATH"
104 |
105 | tar -xvzf "$TMP_DIR/nice-dcv-access-console.tgz" -C "$TMP_DIR"
106 |
107 | # Retrieve required setup information
108 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
109 | region=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
110 | metadata=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/)
111 | if grep -q "public-hostname" <<< "$metadata"; then
112 | acDns=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname)
113 | else
114 | acDns=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-hostname)
115 | fi
116 | smDns=$(aws ssm get-parameter --name dcv-session-manager-dns --region "$region" --with-decryption | grep -Po '"Value": "\K[^"]*')
117 | adminUser=$(aws ssm get-parameter --name dcv-access-console-admin --region "$region" --with-decryption | grep -Po '"Value": "\K[^"]*')
118 | response=$?
119 | if [[ "$response" -ne 0 ]]; then
120 | echo $(date -u) "SSM Parameter for admin not found. Defaulting to ec2-user" | tee -a "$LOG_PATH"
121 | adminUser="ec2-user"
122 | fi
123 | dcvConnGwyCheck=true
124 | dcvConnGwy=$(aws ssm get-parameter --name dcv-connection-gwy-dns --region "$region" --with-decryption | grep -Po '"Value": "\K[^"]*')
125 | response=$?
126 | if [[ "$response" -ne 0 ]]; then
127 | echo $(date -u) "SSM Parameter for DCV Connection Gateway not found. Disabling gateway in configuration." | tee -a "$LOG_PATH"
128 | dcvConnGwyCheck=false
129 | fi
130 | dbPwd=$(openssl rand -base64 12)
131 | pamAuth="system-auth"
132 | CREDS=$(aws ssm get-parameter --name dcv-session-manager-credentials --region "$region" --with-decryption | grep -Po '"Value": "\K[^"]*')
133 | IFS=':'
134 | read -r smClintId smClientPwd <<<"$CREDS"
135 | echo $(date -u) "Configuration discovered:" | tee -a "$LOG_PATH"
136 | echo $(date -u) "AWS Region: $region" | tee -a "$LOG_PATH"
137 | echo $(date -u) "Access Console DNS: $acDns" | tee -a "$LOG_PATH"
138 | echo $(date -u) "Broker DNS: $smDns" | tee -a "$LOG_PATH"
139 | echo $(date -u) "DCV Connection Gateway DNS: $dcvConnGwy" | tee -a "$LOG_PATH"
140 | echo $(date -u) "Admin User: $adminUser" | tee -a $"$LOG_PATH"
141 |
142 | # Set configuration input
143 | jsonPath=$(find "$TMP_DIR" | grep onebox_wizard_input.json)
144 | basePath=$(dirname "$jsonPath")
145 | json=$(cat "$jsonPath")
146 | json=$(jq --arg acDns "$acDns" '."onebox-address" = $acDns' <<<"$json")
147 | json=$(jq --arg smDns "$smDns" '."broker-address" = $smDns' <<<"$json")
148 | json=$(jq --arg smClintId "$smClintId" '."broker-client-id" = $smClintId' <<<"$json")
149 | json=$(jq --arg smClientPwd "$smClientPwd" '."broker-client-password" = $smClientPwd' <<<"$json")
150 | json=$(jq -r '."mariadb-username"="maria"' <<<"$json")
151 | json=$(jq --arg dbPwd "$dbPwd" '."mariadb-password" = $dbPwd' <<<"$json")
152 | json=$(jq --arg adminUser "$adminUser" '."admin-user" = $adminUser' <<<"$json")
153 | if [ $dcvConnGwyCheck ]; then
154 | json=$(jq -r '."enable-connection-gateway"=true' <<<"$json")
155 | json=$(jq --arg dcvConnGwy "$dcvConnGwy" '."connection-gateway-host" = $dcvConnGwy' <<<"$json")
156 | fi
157 | json=$(jq --arg pamAuth $pamAuth '. + {"pam-service-name": $pamAuth}' <<<"$json")
158 | echo "$json" > "$basePath/onebox-config-input.json"
159 |
160 | # Install packages
161 | if [ "$system" = rocky ]; then
162 | sudo setsebool -P httpd_can_network_connect 1
163 | fi
164 | wizardPath=$(find "$TMP_DIR" | grep wizard.py)
165 | cd $basePath
166 | echo $(date -u) "Initiating DCV Access Console installation wizard" | tee -a "$LOG_PATH"
167 |
168 | # Comment out the following command and run manually on Ubuntu
169 | python3 wizard.py --is-onebox --input-json onebox-config-input.json --force
170 |
171 | echo "$json" > /etc/dcv-access-console-auth-server/onebox-config-input-bak.json
172 | echo $(date -u) "Created config backup at /etc/dcv-access-console-auth-server/onebox-config-input-bak.json" | tee -a "$LOG_PATH"
173 |
--------------------------------------------------------------------------------
/cdk/dcv-access-console/stacks/dcv_ac_infra/dcv_ac_infra.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | # this software and associated documentation files (the "Software"), to deal in
5 | # the Software without restriction, including without limitation the rights to
6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | # the Software, and to permit persons to whom the Software is furnished to do so.
8 | #
9 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import os
17 | from aws_cdk import Stack
18 | import aws_cdk as cdk
19 | import aws_cdk.aws_ec2 as ec2
20 | import aws_cdk.aws_iam as iam
21 | import aws_cdk.aws_kms as kms
22 | import aws_cdk.aws_ssm as ssm
23 | from constructs import Construct
24 |
25 | # The DCV Access Console stack
26 | class DcvAccessConsole(Stack):
27 | """ Class to deploy DCV infrastructure components """
28 | def __init__(self, scope: Construct, construct_id: str, config_data: dict, **kwargs) -> None:
29 | super().__init__(scope, construct_id, **kwargs)
30 |
31 | # Create reference for VPC
32 | vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=config_data['network']['vpcId'])
33 | # Create references for target subnet
34 | # using subnet_ids pulled from config.json
35 | subnet_ref = ec2.Subnet.from_subnet_attributes(
36 | self, "SubnetFromAttributes",
37 | subnet_id=config_data['network']['accessConsoleSubnetId'],
38 | availability_zone=config_data['network']['subnetAZ']
39 | )
40 | subnet_target = ec2.SubnetSelection(
41 | subnets=[subnet_ref]
42 | )
43 |
44 | # IAM Fleet Role Configuration
45 | role_access_console = iam.Role(self, "AccessConsoleRole",
46 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
47 | role_name="dcv-access-console-role"
48 | )
49 |
50 | role_access_console.add_managed_policy(
51 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore")
52 | )
53 |
54 | role_access_console.add_to_policy(iam.PolicyStatement(
55 | effect=iam.Effect.ALLOW,
56 | actions=[
57 | 'ssm:DescribeParameters'
58 | ],
59 | resources=[
60 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/*",
61 | ]
62 | ))
63 |
64 | role_access_console.add_to_policy(iam.PolicyStatement(
65 | effect=iam.Effect.ALLOW,
66 | actions=[
67 | 'ssm:GetParameter'
68 | ],
69 | resources=[
70 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/dcv-*",
71 | ]
72 | ))
73 |
74 | # Access Console Security Group configuration
75 | sg_access_console = ec2.SecurityGroup(self, "AccessConsoleSecurityGroup",
76 | vpc=vpc,
77 | description="Security Group for the DCV Access Console",
78 | allow_all_outbound=True, #Egress all
79 | disable_inline_rules=True
80 | )
81 |
82 | # Add Ingress for Access Console
83 | sg_access_console.add_ingress_rule(
84 | ec2.Peer.ipv4(f"{config_data['accessConsole']['inboundAccess']}"), ec2.Port.tcp(443), \
85 | "Allow HTTPS traffic to the DCV Access Console"
86 | )
87 |
88 | # Get KMS Key from Alias/Key Name
89 | kms_arn = f"arn:aws:kms:{self.region}:{self.account}:alias/{config_data['kmsKeyName']}"
90 | kms_key = kms.Key.from_key_arn(self, "kms-key", kms_arn)
91 |
92 | # SSM parameters to hold config values
93 | ssm.StringParameter(self, "brokerCredentials",
94 | description="Client credentials for DCV Session Manager",
95 | parameter_name="dcv-session-manager-credentials",
96 | string_value=f"{config_data['accessConsole']['smClientId']}:{config_data['accessConsole']['smClientPsw']}",
97 | tier=ssm.ParameterTier.STANDARD
98 | )
99 |
100 | ssm.StringParameter(self, "brokerDns",
101 | description="Reachable DNS of DCV Session Manager",
102 | parameter_name="dcv-session-manager-dns",
103 | string_value=f"{config_data['accessConsole']['sessionMgrDns']}",
104 | tier=ssm.ParameterTier.STANDARD
105 | )
106 |
107 | if config_data['accessConsole']['gatewayDns'] != "":
108 | ssm.StringParameter(self, "gwyDns",
109 | description="Reachable DNS of DCV Connection Gateway",
110 | parameter_name="dcv-connection-gwy-dns",
111 | string_value=f"{config_data['accessConsole']['gatewayDns']}",
112 | tier=ssm.ParameterTier.STANDARD
113 | )
114 |
115 | if config_data['accessConsole']['adminUser'] != "ec2-user":
116 | ssm.StringParameter(self, "accessConsoleAdmin",
117 | description="Admin user to set for Access Console",
118 | parameter_name="dcv-access-console-admin",
119 | string_value=f"{config_data['accessConsole']['gatewayDns']}",
120 | tier=ssm.ParameterTier.STANDARD
121 | )
122 |
123 |
124 | # DCV Access Console
125 | ### DCV Access Console AMI
126 | session_mgr_ami = ec2.GenericLinuxImage({
127 | self.region : config_data['accessConsole']['amiId']
128 | }
129 | )
130 |
131 | # Add the user data script to custom string
132 | access_console_user_data_file = open(os.path.join(os.path.dirname( __file__ ),
133 | "..", "..",
134 | "scripts",
135 | "access-console-user-data.sh"),
136 | "r", encoding="utf-8")
137 | access_console_user_data_content = access_console_user_data_file.read()
138 | access_console_user_data = ec2.UserData.custom(access_console_user_data_content)
139 |
140 | # Create a reference to the SSH Key Pair name given in the config.json file
141 | key_pair = ec2.KeyPair.from_key_pair_attributes(self, "DCVKeyPair",
142 | key_pair_name=config_data['sshKeypairName']
143 | )
144 |
145 | # Create the Session Manager EC2 instance
146 | access_console_instance = ec2.Instance(self, "AccessConsoleInstance",
147 | vpc=vpc,
148 | vpc_subnets=subnet_target,
149 | instance_type=ec2.InstanceType.of(
150 | ec2.InstanceClass.M6G, ec2.InstanceSize.LARGE),
151 | machine_image=session_mgr_ami,
152 | security_group=sg_access_console,
153 | key_pair=key_pair,
154 | user_data=access_console_user_data,
155 | role=role_access_console,
156 | block_devices=[ec2.BlockDevice(
157 | device_name="/dev/xvda",
158 | volume=ec2.BlockDeviceVolume.ebs(
159 | 8, encrypted=True, kms_key=kms_key))]
160 | )
161 |
162 | cdk.CfnOutput(self, "AccessConsoleURL", \
163 | value= f"You can access the console at https://{access_console_instance.instance_public_dns_name} or privately at https://{access_console_instance.instance_private_dns_name}")
164 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/README.md:
--------------------------------------------------------------------------------
1 | # Scale Out Deployment of Amazon DCV Connection Gateway, Sessions Manager, and Broker
2 |
3 | Accelerate cloud deployment of foundational autoscaling infrastructure for [Amazon DCV](https://aws.amazon.com/hpc/dcv/) with AWS Cloud Development Kit (AWS CDK). AWS CDK will create EC2 Image builder pipelines to create images to run DCV components on Amazon Elastic Compute Cloud (Amazon EC2).
4 |
5 | ## Overview
6 | The architecture diagram below depicts the resources that this solution will deploy into your account.
7 | >Note: A DCV fleet will need to be spun up in conjunction with this solution. For testing this solution, one will be created near the end of the procedure below.
8 |
9 | 
10 | Figure 1: AWS CDK that will setup the image build process and foundational infrastructure for a scale out solution of Amazon DCV Connection Gateway and Session Manager.
11 |
12 | ## Prerequisites
13 | - An AWS account with full permissions on:
14 | - Amazon EC2 Image Builder
15 | - AWS Systems Manager (AWS SSM) Parameter Store
16 | - AWS SSM Session Manager
17 | - Amazon Elastic Compute Cloud (Amazon EC2)
18 | - Amazon Virtual Private Cloud (Amazon VPC)
19 | - A system with the following installed:
20 | - AWS CLI
21 | - AWS CDK
22 | - Node.js
23 | - Python
24 | - Git
25 | - Basic understanding of:
26 | - Image building
27 | - AWS Cloud
28 | - Scripting languages (Python, Bash)
29 | - DCV
30 |
31 | >Note: See Testing Prerequisites for additional items
32 |
33 | # EC2 Image Builder Pipeline
34 | This example will create:
35 | - Two EC2 Image Builder Pipelines to build the DCV images; one for DCV Session Manager and one for DCV Connection Gateway
36 |
37 | There are two image builder pipelines that will be created:
38 | - Session Manager
39 | - Connection Gateway
40 |
41 | >Note: If you do not provide a target VPC, a default VPC is required for the EC2 Image Builder Pipeline. If your environment doesn't have a default VPC, you will receive an error message similar to "...An error occurred (VPCIdNotSpecified) when calling the RunInstances operation: No default VPC for this user..." when invoking the pipeline.
42 |
43 | # AWS VPC Infrastructure Creation with CDK
44 | This example contains:
45 | - Choice of VPC and Subnets
46 | - If you do not specify a VPC, the CDK will create:
47 | - A new VPC with an Internet Gateway
48 | - Public and Private subnets
49 | - Two availability zones
50 | - NAT Gateway
51 | - A security groups for DCV Connection Gateway, DCV Session Manager, and DCV Server
52 | - IAM roles required for configuration
53 | - Network Load Balancer for DCV Connection Gateway
54 | - Autoscaling Groups for the DCV Connection Gateway instances
55 | - This solution will initialize the autoscaling group with one Connection Gateway instance per availability zone
56 | - Autoscaling based off of CPU consumption
57 | - SSM Parameter Store parameter to hold the broker DNS
58 |
59 | >Note: An SSH key-pair (.pem or .ppk) is required to be registered in your AWS account and region. This key-pair name is required within the `config.json` file before deploying the infrastructure stack in order to allow SSH access into the instances. AWS SSM can also be used for terminal access.
60 |
61 | ## Step 1: NPM
62 | The LTS version of [npm](https://www.npmjs.com/) is recommended. If npm is already on your system, upgrade npm to the latest version.
63 | npm install -g npm@latest
64 |
65 | ```bash
66 | npm install -g npm@latest
67 | ```
68 |
69 | ## Step 2: AWS CDK
70 |
71 | Ensure that the latest [aws-cdk](https://aws.amazon.com/cdk/) is installed.
72 |
73 | ```bash
74 | npm install -g aws-cdk
75 | ```
76 |
77 | Once installed, the command cdk --version will confirm installation was successful.
78 |
79 | ```bash
80 | cdk --version
81 | ```
82 |
83 | ## Step 3: AWS CLI
84 | Install [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
85 |
86 |
87 | ## Step 4: Git
88 | Install [Git](https://git-scm.com/)
89 |
90 | ## Step 5: Clone the Repository
91 | Visit [clone a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) for instructions. Clone this repository locally.
92 |
93 | ## Step 6: Create a virtual environment
94 | Open up a command line terminal of your choice. Change directory into the cloned repository.
95 | ### Windows
96 | ```bash
97 | virtualenv --python dcv-env
98 | .\dcv-env\Scripts\activate
99 | ```
100 | ### macOS/Linux
101 | ```bash
102 | virtualenv --python dcv-env
103 | source dcv-env/bin/activate
104 | ```
105 |
106 | ## Step 7: Install Project Dependencies
107 | Install project dependencies by running the following command.
108 |
109 | ```bash
110 | pip install -r requirements.txt
111 | ```
112 |
113 | ## Step 8: Assume IAM role
114 | [Use an IAM role in the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html).
115 | > Note: To confirm your credentials are associated with the correct AWS account, you can run the following AWS CLI command -
116 | ```bash
117 | aws sts get-caller-identity
118 | ```
119 | (See [get-caller-identity](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/get-caller-identity.html) in the AWS CLI documentation).
120 |
121 | ## Step 9: CDK Bootstrap
122 | [Bootstrap your AWS CDK environment. ](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-bootstrap)
123 | Replace with your desired account number and region.
124 | ```bash
125 | cdk bootstrap 1234567890/us-east-1
126 | ```
127 |
128 | > Note: sess_manager_ami and conn_gateway_ami will need to get updated with AMI IDs after deploying SessionMgrAmiStack and ConnectionGwyAmiStack stacks and running their pipelines.
129 |
130 | ## Step 10: Set AWS Account and Region for Infrastructure
131 | Set the AWS account id and region by specifying in `config.json`
132 | ```bash
133 | {
134 | ...
135 | "accountId": "xxxxxxxxxxxx",
136 | "region": "xxxxxxxxxxxxxxx",
137 | ...
138 | }
139 | ```
140 | Also, be sure the region is set in your AWS credentials by running the following command by replacing `us-east-1` with your intended region:
141 |
142 | For Windows:
143 | ```powershell
144 | set AWS_REGION=us-east-1
145 | ```
146 | For Mac/Linux:
147 | ```bash
148 | export AWS_REGION=us-east-1
149 | ```
150 |
151 | ## Step 11: Check Project with Synth
152 | Verify there are no errors with the cloned project with [cdk synth](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-synth) (synthesize).
153 | ```bash
154 | cdk synth --all
155 | ```
156 |
157 | ## Step 12: Deploy Session Manager stack
158 | The CDK will create the DCV Sessions Manager EC2 Image Builder Pipeline.
159 | ```bash
160 | cdk deploy SessionMgrAmiStack
161 | ```
162 |
163 | ## Step 13: Deploy Connection Gateway stack
164 | The CDK will create the DCV Connection Gateway EC2 Image Builder Pipeline.
165 | ```bash
166 | cdk deploy ConnectionGwyAmiStack
167 | ```
168 |
169 | ## Step 14: Run the EC2 Builder Pipelines
170 | Run pipelines to create the AMIs for the Sessions Manager and the Connection Gateway.
171 |
172 |
173 | ### Option 1: Running Pipeline from AWS CLI
174 |
175 | Run the following command to run the pipeline. Replace the ``, ``, and `` with your values. The pipeline names are `dcv-connection-gwy-ami-pipeline` or `dcv-session-mgr-ami-pipeline`.
176 |
177 | ```bash
178 | aws imagebuilder start-image-pipeline-execution \
179 | --image-pipeline-arn arn:aws:imagebuilder:::image-pipeline/
180 | ```
181 |
182 |
183 | The cdk outputs the values to run the pipeline using the AWS CLI.
184 |
185 | - Run the dcv-sess-mgr pipeline first
186 | - If successful, run the dcv-conn-gateway pipeline
187 | - Take note of the AMI IDs created
188 |
189 | **Example:** Using the AWS CLI to run the image pipeline.
190 | ```bash
191 | aws imagebuilder start-image-pipeline-execution --image-pipeline-arn arn:aws:imagebuilder:::image-pipeline/pipeline-dcv-conn-gateway
192 |
193 | ```
194 |
195 | **Example:** Using the AWS CLI to get the AMI ID from the pipeline build.
196 |
197 | ```bash
198 | aws imagebuilder list-image-build-versions --image-version-arn arn:aws:imagebuilder:::image/recipe-dcv-sess-mgr/1.0.0 | grep ami-
199 |
200 | ```
201 |
202 | Example sample output
203 | ```bash
204 | "image": "ami-1234567890abcdef0",
205 | ```
206 | The AMI ID response value will be added in the config.json file in Step 14.
207 |
208 | ### Option 2: Use the **Run pipeline** action in the AWS Management Console.
209 |
210 | For more information, see *Run your image pipeline* in the [EC2 Image Builder User Guide](https://docs.aws.amazon.com/imagebuilder/latest/userguide/pipelines-run.html).
211 |
212 | 
213 |
214 | - Run the dcv-sess-mgr pipeline first
215 | - If successful, run the dcv-conn-gateway pipeline
216 | - Take note of the AMI IDs created
217 |
218 |
219 | ## Step 15: Add AMI IDs into the CDK project
220 |
221 | Locate and note the AMI ID for each of your pipelines. Your images can be found on the *Images* page in the [EC2 Image Builder Console](https://console.aws.amazon.com/imagebuilder/home?#/images). For more information, see the *List images and build versions* section of the [EC2 Image Builder User Guide](https://docs.aws.amazon.com/imagebuilder/latest/userguide/image-details-list.html).
222 |
223 | Update `config.json` with the AMI IDs from each of your pipelines. Update sess_manager_ami and conn_gateway_ami values.
224 |
225 | Example config.json
226 |
227 | ```bash
228 | {
229 | "accountId": "xxxxxxxxxxxx",
230 | ...
231 | "connectionGwy" : {
232 | ...
233 | "builderAmiId": "ami-xxxxxxxxxxxxxxxxx"
234 | }
235 | ```
236 |
237 | ## Step 16: Key Pairs for EC2
238 | Use your own Key Pair or [Create Key Pairs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-key-pairs.html) for accessing the EC2s.
239 |
240 | Use the Key Pair value for ssh_keypair_name in `config.json`
241 | ```bash
242 | {
243 | "accountId": "xxxxxxxxxxxx",
244 | ...
245 | "sshKeypairName": "xxxxxxxxxxxxxxx",
246 | ...
247 | }
248 | ```
249 |
250 | ## Step 17: AWS Key Management Service (KMS)
251 | Choose to use the AWS provide default KMS or [Create Keys](href="https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html).
252 |
253 | Use the KMS value for kms_key_name in `config.json`
254 |
255 | ```bash
256 | {
257 | "accountId": "xxxxxxxxxxxx",
258 | ...
259 | "kmsKeyName": "aws/ebs",
260 | ...
261 | }
262 | ```
263 |
264 | ## Step 18: Deploy Infrastructure stack
265 | ```bash
266 | cdk deploy DcvInfraStack
267 | ```
268 |
269 | ## Step 19: Testing Your Configuration
270 | Now that your infrastructure is created, you must create a DCV session on a DCV server to connect to. For this step, [DCV Session Manager CLI](https://docs.aws.amazon.com/dcv/latest/sm-cli/sm-cli-reference.html) is required, as well as a [DCV Server](https://docs.aws.amazon.com/dcv/latest/adminguide/servers.html). Alteratively, you may deploy DCV Access Console. Use the instructions below to test your deployment.
271 |
272 | ### Testing Prerequisites
273 | There are several ways testing can be performed, but this guide uses [AWS Systems Manager Session Manager](https://aws.amazon.com/systems-manager/) and the CDK provides IAM permissions to use it.
274 |
275 | ### Launch a DCV Server Fleet Instance
276 | Once your CDK deployed instances are passing EC2 health checks, a DCV fleet server is required to be launched. The DCV server also needs to have the DCV Session Manager agent installed. With both of these components configured, the instance will check in with the DCV Session Manager broker so sessions on the instance can be managed by the broker.
277 |
278 | **Note:** You will need to manage the user accounts on the DCV servers. If you do not have a centralized identity (e.g. Microsoft Active Directory), you need to create a local user and set a password. The default user for Windows is `Administrator` and the default user for Amazon Linux 2 is `ec2-user`. You can create new users or update passwords by using AWS Systems Manager Session Manager for remote access.
279 |
280 | #### Windows
281 | To bootstrap a Windows DCV server, first download the [Install-DCVandSMAgent.ps1](/bootstrap/Install-DCVandSMAgent.ps1) script from the bootstrap folder of dcv-samples. Once downloaded, update the `SESSION-MGR-PRIVATE-DNS` placeholder with the private DNS name of your DCV Session Manager instance. This can be retrieved from the EC2 console. Deploy a new Windows-based instance within a private subnet and inject the script content in the **User data** field. Ensure you have chosen a base image that is [supported by DCV server](https://docs.aws.amazon.com/dcv/latest/adminguide/servers.html). The CDK provisioned a DCV server security group named `DcvInfraStack-DCVServerSecurityGroup*`. The CDK also created an instance profile named `dcv-fleet-role`.
282 |
283 | #### Linux
284 | To bootstrap a Windows DCV server, first download the [linux-config-sessionmgr-agent.sh](/bootstrap/linux-config-sessionmgr-agent.sh) script from the bootstrap folder of dcv-samples. Once downloaded, update the `SESSION-MGR-PRIVATE-DNS` placeholder with the private DNS name of your DCV Session Manager instance. This can be retrieved from the EC2 console. By default, Linux operating systems do not provide a desktop environment. For simplicity, you may use the [AWS Marketplace DCV AMI for Amazon Linux 2](https://aws.amazon.com/marketplace/seller-profile?id=74eff437-1315-4130-8b04-27da3fa01de1). Deploy a new instance based on the Marketplace AMI within a private subnet and inject the script content in the **User data** field. If you use an alternative image, ensure you have chosen a base image that is [supported by DCV server](https://docs.aws.amazon.com/dcv/latest/adminguide/servers.html). The CDK provisioned a DCV server security group named `DcvInfraStack-DCVServerSecurityGroup*`. The CDK also created an instance profile named `dcv-fleet-role`.
285 |
286 | When your newly deployed instance is passing EC2 health checks, proceed to the next step.
287 |
288 | ### Register an API Client on Session Manager Instance
289 | 1. Access your DCV Session Manager instance using Systems Manager Session Manager.
290 | 2. To make API calls to your broker, you will need to [register an API client](https://docs.aws.amazon.com/dcv/latest/sm-admin/register-api-client.html). To generate these credentials, run the following command.
291 | > IMPORTANT: These credentials cannot be retrieved later so take note of the response. You will need to rerun this command if you lose the credentials.
292 |
293 | ```bash
294 | sudo -u root dcv-session-manager-broker register-api-client --client-name client_name
295 | ```
296 | 3. Record the printed credentials and exit out of Sessions Manager SSH session
297 |
298 | ### Communicating with the broker
299 |
300 | #### Option 1: Deploy the DCV Access Console
301 | The [DCV Access Console](https://docs.aws.amazon.com/dcv/latest/access-console/what-is-access-console.html) is a web application that helps administrators and end users manage their DCV sessions. To deploy the DCV Access Console, see the [CDK README](/cdk/README.md) or [administrator guide](https://docs.aws.amazon.com/dcv/latest/access-console/setup.html).
302 |
303 | #### Option 2: Download and Configure the DCV Session Manager CLI
304 | The [DCV Session Manager Command Line Interface (CLI)](https://docs.aws.amazon.com/dcv/latest/sm-cli/what-is-sm-cli.html) is used to interact with a DCV Session Manager broker using commands in your command-line shell. The CDK allows access from the DCV Connection Gateway instances. Alternatively, you may run the CLI on the Session Manager instance.
305 |
306 | 1. Download the DCV Session Manager CLI with the following command:
307 | ```bash
308 | wget https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-session-manager-cli.zip
309 | ```
310 |
311 | 2. Unzip the CLI package with the following command:
312 | ```bash
313 | unzip nice-dcv-session-manager-cli.zip
314 | ```
315 |
316 | 3. Configure the CLI ```dcvsmcli.conf``` file. See the [CLI guide](https://docs.aws.amazon.com/dcv/latest/sm-cli/configuration-file.html) for a reference. You will need to have the following configuration set.
317 |
318 | ```json
319 | [output]
320 | # The formatting style for command output.
321 | output-format = json
322 |
323 | # Turn on debug logging
324 | #debug = true
325 |
326 | [security]
327 | # Disable SSL certificates verification.
328 | no-verify-ssl = true
329 |
330 | # CA certificate bundle to use when verifying SSL certificates.
331 | #ca-bundle = ca-bundle.pem
332 |
333 | [authentication]
334 | # hostname of the authentication server used to request the token
335 | #auth-server-url = https://broker-host:broker-port/oauth2/token?grant_type=client_credentials
336 |
337 | # The client ID
338 | client-id = CLIENT_ID_FROM_REGISTRATION
339 |
340 | # The client password
341 | client-password = CLIENT_PASSWORD_FROM_REGISTRATION
342 |
343 | [broker]
344 | # hostname or IP of the broker
345 | url = https://DNSorIP-DCVSessionMgr:8443
346 | ```
347 |
348 | 4. Test your CLI install and ensure the DCV server is checked in with the broker by running the following command. This should return the DCV Fleet instance. Run the following commands from within the CLI unzipped folder.
349 | ```bash
350 | python3 dcvsm describe-servers
351 | ```
352 | - Output should return an available server in the JSON
353 | - If no servers are available, follow the **Troubleshooting DCV Fleet Session Manager Creation Errors** section below.
354 |
355 | 5. Run the following command to have DCV Session Manager create a DCV session on the DCV Server you deployed. Take note of the `"successful_list": "id"` (*not* `request_id`) in the call response.
356 | >Note: Be sure to enter the fleet instance ID in the `requirements` argument. For additional requirements, see [DCV Session Manager Developer Guide](https://docs.aws.amazon.com/dcv/latest/sm-dev/CreateSessions.html#request). The placeholder *LOCALUSER* should be replaced with the user on the instance you plan to login with.
357 |
358 | ```bash
359 | python3 dcvsm create-session --name Testing --owner LOCALUSER --type Console --requirements "server:Host.Aws.Ec2InstanceId = 'i-XXXXXXXXXXXXXXXXX'"
360 | ```
361 | 6. Run the following command to retrieve the DCV session’s authentication token specific to the connecting user. Take note of the token in the response.
362 | >Note: Be sure to enter the `session-id` below from the previous step.
363 | ```bash
364 | python3 dcvsm get-session-connection-data --session-id --user LOCALUSER
365 | ```
366 | - Take note the `connection_token` in the response.
367 | 7. You can initiate a connection from a DCV client using the session ID and authentication code. The [connection string](https://docs.aws.amazon.com/dcv/latest/sm-dev/GetSessionConnectionData.html#additional-info) should be formatted as:
368 | - `Connection-Gateway-NLB-DNSorIP:8443/?authToken=TOKEN#SESSION-ID`
369 | - Replace `TOKEN` with the `connection_token` retrieved from the previous call.
370 | - Replace `SESSION-ID` with the session ID returned when you created the session.
371 | - **Note:** you must initiate the call from a [DCV client](https://docs.aws.amazon.com/dcv/latest/userguide/client.html).
372 | 8. Once your connection is established, log in to your DCV Fleet Server with the instance credentials.
373 |
374 | ## Cleanup Your Environment
375 | To destroy all infrastructure contained in the CDK, run the following command:
376 | - Be sure to terminate and remove bastion resources manually created (e.g. instances, security groups, etc.) that were used in testing (any infrastructure outside of the CDK project, but within the VPC) before running the command below.
377 | - You will need to delete the SSM Parameter for the broker private ip named `dcv-broker-private-ip-*`.
378 | ```bash
379 | # Destroy all project resources.
380 | cdk destroy --all
381 | ```
382 |
383 | ## Troubleshooting DCV Fleet Session Manager Creation Errors
384 | 1. List all sessions. Output should be a list of DCV sessions.
385 | ```bash
386 | python3 dcvsm describe-sessions
387 | ```
388 | 2. Check the CLI can find DCV servers. Output should be an available server in the JSON.
389 | ```bash
390 | python3 dcvsm describe-servers
391 | ```
392 | 3. Check the Agent is running. Output should be "Success".
393 | ```bash
394 | grep 'sessionsUpdateResponse' /var/log/dcv-session-manager-agent/agent.log | tail -1 | grep -o success`
395 | ```
396 | 4. Check the Broker is running. Output should be { "error": "No authorization header"}
397 | >Note: Be sure to fill in the correct private IP address and region from the Session Manager instance below in `X-X-X-X.xx-xxxx-x`. (e.g. `10-0-2-63.us-west-2`)
398 | ```bash
399 | curl -X GET https://BROKER_DNS:8443/sessionConnectionData/aSession/aOwner --insecure
400 | ```
401 | For more information, see the *Verify the installations* page of the [DCV Session Manager Administrator guide](https://docs.aws.amazon.com/dcv/latest/sm-admin/verify.html).
402 |
403 | ## Authors and acknowledgment
404 | [Andrew Morgan](https://github.com/morgnza)
405 | [Eric Cornwell](https://github.com/Eecornwell)
406 |
407 | ## License
408 | MIT License
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/app.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | # this software and associated documentation files (the "Software"), to deal in
5 | # the Software without restriction, including without limitation the rights to
6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | # the Software, and to permit persons to whom the Software is furnished to do so.
8 | #
9 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import os
17 | import json
18 | import aws_cdk as cdk
19 | from stacks.dcv_ami.dcv_ami import DcvAmi
20 | from stacks.dcv_infra.dcv_infra import DcvInfra
21 |
22 | app = cdk.App()
23 |
24 | # Load the app configuration from the config.json file
25 | try:
26 | with open("config.json", "r", encoding="utf-8") as config_file:
27 | config_data = dict(json.load(config_file))
28 | except Exception as e:
29 | print(f"Could not read the app configuration file. {e}")
30 | raise e
31 |
32 | # Get the contents of the Session Manager component file
33 | session_mgr_component = open(os.path.join(os.path.dirname( __file__ ),
34 | "components",
35 | "build-dcv-session-mgr.yaml"),
36 | "r", encoding="utf-8").read()
37 |
38 | # Get the contents of the Connection Gateway component file
39 | connection_gwy_component = open(os.path.join(os.path.dirname( __file__ ),
40 | "components",
41 | "build-dcv-connection-gwy.yaml"),
42 | "r", encoding="utf-8").read()
43 |
44 | # Set CDK environment variables
45 | environment = cdk.Environment(account=config_data['accountId'], region=config_data['region'])
46 |
47 | # Create the DCV AMI Builder Stack for Session Manager
48 | session_mgr_ami = DcvAmi(app, "SessionMgrAmiStack",
49 | description='(uksb-1tupboc66) (tag:dcv-session-mgr-pipeline)',
50 | image_pipeline_name="dcv-session-mgr-ami",
51 | component_content=session_mgr_component,
52 | instance_type="m6g.large",
53 | config_data=config_data,
54 | env=environment)
55 |
56 | # Create the DCV AMI Builder Stack for Connection Gateway
57 | connection_gwy_ami= DcvAmi(app, "ConnectionGwyAmiStack",
58 | description='(uksb-1tupboc66) (tag:dcv-connection-gwy-pipeline)',
59 | image_pipeline_name="dcv-connection-gwy-ami",
60 | component_content=connection_gwy_component,
61 | instance_type="c7g.large",
62 | config_data=config_data,
63 | env=environment)
64 |
65 | # Create the DCV Infrastructure Stack for Session Manager and Connection Gateway
66 | DcvInfra(app, "DcvInfraStack",
67 | description='(uksb-1tupboc66) (tag:dcv-gw-sm-with-pipelines)',
68 | config_data=config_data,
69 | env=environment)
70 |
71 | app.synth()
72 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/cdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": "python app.py",
3 | "watch": {
4 | "include": [
5 | "**"
6 | ],
7 | "exclude": [
8 | "README.md",
9 | "cdk*.json",
10 | "requirements*.txt",
11 | "**/__init__.py",
12 | "**/__pycache__"
13 | ]
14 | },
15 | "context": {
16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
17 | "@aws-cdk/core:checkSecretUsage": true,
18 | "@aws-cdk/core:target-partitions": [
19 | "aws",
20 | "aws-cn"
21 | ],
22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
25 | "@aws-cdk/aws-iam:minimizePolicies": true,
26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
31 | "@aws-cdk/core:enablePartitionLiterals": true,
32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
33 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true,
34 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
35 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
36 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
37 | "@aws-cdk/aws-route53-patters:useCertificate": true,
38 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false,
39 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
40 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
41 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
42 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
43 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
44 | "@aws-cdk/aws-redshift:columnId": true,
45 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
46 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
47 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
48 | "@aws-cdk/aws-kms:aliasNameRef": true,
49 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
50 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
51 | "@aws-cdk/aws-efs:denyAnonymousAccess": true,
52 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
53 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
54 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
55 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
56 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
57 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
58 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/components/build-dcv-connection-gwy.yaml:
--------------------------------------------------------------------------------
1 | name: DCVConnGatewayInstallBuildDocument
2 | description: This is a build document for NICE DCV Connection Gateway installation.
3 | schemaVersion: 1.0
4 | phases:
5 | - name: build
6 | steps:
7 | - name: UpdateOS
8 | action: UpdateOS
9 | timeoutSeconds: -1
10 | onFailure: Continue
11 | maxAttempts: 3
12 | inputs:
13 | exclude:
14 | - amazon-ssm-agent
15 | - name: CreateLogFile
16 | action: CreateFile
17 | inputs:
18 | - path: /var/log/dcv-connection-gwy-install.log
19 | content:
20 | overwrite: true
21 | - name: CreateTempFolder
22 | action: CreateFolder
23 | inputs:
24 | - path: /tmp/DCVGW/
25 | - name: DownloadDCVConnGateway
26 | action: WebDownload
27 | maxAttempts: 3
28 | inputs:
29 | - source: https://raw.githubusercontent.com/aws-samples/dcv-samples/main/bootstrap/dcv-gateway-installer.sh
30 | destination: /tmp/DCVGW/
31 | - name: InstallDCVConnGateway
32 | action: ExecuteBash
33 | inputs:
34 | commands:
35 | - set -eE
36 | - LOG_PATH="/var/log/dcv-connection-gwy-install.log"
37 | - echo $(date -u) "Starting NICE DCV Connection Gateway installation..." | tee -a $LOG_PATH
38 | - cd /tmp/DCVGW/
39 | - echo $(date -u) "Installing Connection Gateway package..." | tee -a $LOG_PATH
40 | - chmod +x dcv-gateway-installer.sh
41 | - sudo /bin/bash /tmp/DCVGW/dcv-gateway-installer.sh
42 | - echo $(date -u) "Installed Connection Gateway package..." | tee -a $LOG_PATH
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/components/build-dcv-session-mgr.yaml:
--------------------------------------------------------------------------------
1 | name: DCVSessMgrInstallBuildDocument
2 | description: This is a build document for NICE DCV Session Manager installation.
3 | schemaVersion: 1.0
4 | phases:
5 | - name: build
6 | steps:
7 | - name: UpdateOS
8 | action: UpdateOS
9 | timeoutSeconds: -1
10 | onFailure: Continue
11 | maxAttempts: 3
12 | inputs:
13 | exclude:
14 | - amazon-ssm-agent
15 | - name: CreateLogFile
16 | action: CreateFile
17 | inputs:
18 | - path: /var/log/dcv-session-mgr-install.log
19 | content:
20 | overwrite: true
21 | - name: CreateTempFolder
22 | action: CreateFolder
23 | inputs:
24 | - path: /tmp/DCVSM/
25 | - name: DownloadDCVSessMgr
26 | action: WebDownload
27 | maxAttempts: 3
28 | inputs:
29 | - source: https://raw.githubusercontent.com/aws-samples/dcv-samples/main/bootstrap/dcv-session-manager-installer.sh
30 | destination: /tmp/DCVSM/
31 | - name: InstallDCVSessMgr
32 | action: ExecuteBash
33 | inputs:
34 | commands:
35 | # Set the installation log and current directory
36 | - LOG_PATH="/var/log/dcv-session-mgr-install.log"
37 | - echo $(date -u) "Starting NICE DCV Session Manager installation..." | tee -a $LOG_PATH
38 | # Install the broker package
39 | - chmod +x /tmp/DCVSM/dcv-session-manager-installer.sh
40 | - /bin/bash /tmp/DCVSM/dcv-session-manager-installer.sh
41 | - name: ConfigureDCVSessMgr
42 | action: ExecuteBash
43 | inputs:
44 | commands:
45 | - LOG_PATH="/var/log/dcv-session-mgr-install.log"
46 | - echo $(date -u) "Configuring DCV Session Manager..." | tee -a $LOG_PATH
47 | - CONFIG_PATH="/etc/dcv-session-manager-broker/session-manager-broker.properties"
48 | # Get the current region so we know where to put cert content secret
49 | - |
50 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
51 | - |
52 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
53 | # Enable the gateway in config
54 | - sed -i '/^enable-gateway/s/=.*$/= true/' $CONFIG_PATH
55 | # Uncomment the broker connector host and port in config
56 | - sed -i '/gateway-to-broker-connector-https-port/s/^#\s//g' $CONFIG_PATH
57 | - sed -i '/gateway-to-broker-connector-bind-host/s/^#\s//g' $CONFIG_PATH
58 | # Enable the broker to persist on DynamoDB in config
59 | - sed -i '/^enable-persistence/s/=.*$/= true/' $CONFIG_PATH
60 | # Uncomment database, region, Read Capacity Units(RCU), Write Capacity Units(WCU), and table name prefix in config
61 | - sed -i '/persistence-db/s/^#\s//g' $CONFIG_PATH
62 | - sed -i '/dynamodb-region/s/^#\s//g' $CONFIG_PATH
63 | - sed -i '/dynamodb-table-rcu/s/^#\s//g' $CONFIG_PATH
64 | - sed -i '/dynamodb-table-wcu/s/^#\s//g' $CONFIG_PATH
65 | - sed -i '/dynamodb-table-name-prefix/s/^#\s//g' $CONFIG_PATH
66 | # Be sure the region is correct and not the default in the file
67 | - sed -i "/^dynamodb-region/s/=.*$/= $REGION/" $CONFIG_PATH
68 | # Restart the broker service
69 | - systemctl restart dcv-session-manager-broker.service
70 | - echo $(date -u) "DCV Session Manager Installation and Configuration complete..." | tee -a $LOG_PATH
71 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "comment": "NOTE: BEFORE DEPLOYING SESSION MANAGER AND CONNECTION GATEWAY STACK, UPDATE THE ACCOUNT ID AND REGION BELOW",
3 | "accountId": "xxxxxxxxxxxx",
4 | "region": "xx-xxxx-x",
5 | "sshKeypairName": "",
6 | "kmsKeyName": "aws/ebs",
7 | "network" : {
8 | "vpcId": "",
9 | "publicASubnetId": "",
10 | "publicBSubnetId": "",
11 | "privateASubnetId": "",
12 | "privateBSubnetId": ""
13 | },
14 | "sessionMgr" : {
15 | "baseAmiId": "ami-xxxxxxxxxxxxxxxxx",
16 | "comment": "NOTE: BEFORE DEPLOYING INFRA STACK AND AFTER DEPLOYING THE SESSION MANAGER & CONNECTION GATEWAY STACK, UPDATE THE AMI ID BELOW",
17 | "builderAmiId": "ami-xxxxxxxxxxxxxxxxx"
18 | },
19 | "connectionGwy" : {
20 | "baseAmiId": "ami-xxxxxxxxxxxxxxxxx",
21 | "comment": "NOTE: BEFORE DEPLOYING INFRA STACK AND AFTER DEPLOYING THE SESSION MANAGER & CONNECTION GATEWAY STACK, UPDATE THE AMI ID BELOW",
22 | "builderAmiId": "ami-xxxxxxxxxxxxxxxxx"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/documentation/images/EC2ImageBuilderRunPipeline.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/dcv-samples/62554cb1deb94b843a7faceb94ff774b94f73243/cdk/dcv-gw-sm-with-pipelines/documentation/images/EC2ImageBuilderRunPipeline.jpg
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/documentation/images/SolutionArchitecture.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/dcv-samples/62554cb1deb94b843a7faceb94ff774b94f73243/cdk/dcv-gw-sm-with-pipelines/documentation/images/SolutionArchitecture.PNG
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/requirements.txt:
--------------------------------------------------------------------------------
1 | aws-cdk-lib>=2.141.0
2 | constructs>=10.0.0,<11.0.0
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/scripts/connection-gwy-user-data.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | # this software and associated documentation files (the "Software"), to deal in
6 | # the Software without restriction, including without limitation the rights to
7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | # the Software, and to permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
12 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
14 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | LOG_PATH="/var/log/dcv-connection-gwy-install.log"
18 | echo $(date -u) "*****START USER DATA SCRIPT*****" | tee -a "$LOG_PATH"
19 |
20 | # Get current region
21 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
22 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
23 | echo $(date -u) "Current Region: $REGION" | tee -a "$LOG_PATH"
24 |
25 | # Retrieve Broker Private DNS from SSM Parameter Store
26 | echo $(date -u) "Retrieving broker private DNS from SSM Parameter Store" | tee -a "$LOG_PATH"
27 | BROKER_PRIVATE_DNS=$(aws ssm get-parameter --name dcv-broker-private-dns --region "$REGION" --with-decryption | grep -Po '"Value": "\K[^"]*')
28 | timeout 1 bash -c "/dev/tcp/$BROKER_PRIVATE_DNS/8447"
29 | RESPONSE="$?"
30 | while [ "$RESPONSE" != 0 ]; do
31 | echo $(date -u) "Unable to reach broker. Waiting before retry." | tee -a "$LOG_PATH"
32 | sleep 15s
33 | BROKER_PRIVATE_DNS=$(aws ssm get-parameter --name dcv-broker-private-dns --region "$REGION" --with-decryption | grep -Po '"Value": "\K[^"]*')
34 | timeout 1 bash -c "cat < /dev/null > /dev/tcp/$BROKER_PRIVATE_DNS/8447"
35 | RESPONSE="$?"
36 | done
37 | echo $(date -u) "Broker private DNS found $BROKER_PRIVATE_DNS" | tee -a "$LOG_PATH"
38 |
39 | # Port Configuration. Using hex to escape double quotes: \x22 = "
40 | echo $(date -u) "Configuring Connection Gateway..." | tee -a "$LOG_PATH"
41 | sed -i "s/^#\[health-check\]/\[health-check\]/g" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
42 | sed -i --expression 's|#bind-addr = "::"|bind-addr = "::"|' /etc/dcv-connection-gateway/dcv-connection-gateway.conf
43 | sed -i --expression 's|#tls-strict = false|tls-strict = false|' /etc/dcv-connection-gateway/dcv-connection-gateway.conf
44 | sed -i "/\[resolver\]/a tls-strict = false" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
45 | sed -i "/bind-addr = \"::\"/a port = 8989" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
46 | sed -i "s|url = \"https://localhost:8081\"|url = \"https://$BROKER_PRIVATE_DNS:8447\"|" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
47 |
48 | # Start DCV Connection Gateway Service
49 | echo $(date -u) "Starting and Enabling Connection Gateway service..." | tee -a "$LOG_PATH"
50 | systemctl restart dcv-connection-gateway.service
51 |
52 | # Log if successful installation
53 | if [[ $? -eq 0 ]]; then
54 | echo $(date -u) "Successfully installed DCV Connection Gateway" | tee -a "$LOG_PATH"
55 | else
56 | echo $(date -u) "There was an error during DCV Connection Gateway installation" | tee -a "$LOG_PATH"
57 | fi
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/scripts/session-mgr-user-data.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | # this software and associated documentation files (the "Software"), to deal in
6 | # the Software without restriction, including without limitation the rights to
7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | # the Software, and to permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
12 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
14 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | LOG_PATH="/var/log/dcv-session-mgr-install.log"
18 | echo $(date -u) "*****START USER DATA SCRIPT*****" | tee -a "$LOG_PATH"
19 |
20 | # Get the private IP for connection gateway to use during configuration
21 | echo $(date -u) "Retrieving private broker DNS..." | tee -a "$LOG_PATH"
22 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
23 | MAC=`curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/network/interfaces/macs/`
24 | PRIVATE_DNS=`curl -H "X-aws-ec2-metadata-token: $TOKEN" "http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}local-hostname"`
25 | echo $(date -u) "Using private DNS $PRIVATE_DNS" | tee -a "$LOG_PATH"
26 |
27 | # Get current region
28 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
29 | echo $(date -u) "Current Region: $REGION" | tee -a "$LOG_PATH"
30 |
31 | # Store the private private DNS name in SSM Parameter Store
32 | echo $(date -u) "Storing broker private DNS name in AWS SSM Parameter Store..." | tee -a "$LOG_PATH"
33 | aws ssm put-parameter --name dcv-broker-private-dns --value "$PRIVATE_DNS" --type String --overwrite --region "$REGION"
34 | # Log if successful installation
35 | if [[ $? -eq 0 ]]; then
36 | echo $(date -u) "Stored private DNS name $PRIVATE_DNS in Parameter Store" | tee -a "$LOG_PATH"
37 | # Restart the broker service for the new config to get pulled
38 | systemctl restart dcv-session-manager-broker.service
39 | echo $(date -u) "Successfully installed DCV Session Manager" | tee -a "$LOG_PATH"
40 | else
41 | echo $(date -u) "There was an error during DCV Session Manager installation" | tee -a "$LOG_PATH"
42 | fi
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/stacks/dcv_ami/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/dcv-samples/62554cb1deb94b843a7faceb94ff774b94f73243/cdk/dcv-gw-sm-with-pipelines/stacks/dcv_ami/__init__.py
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/stacks/dcv_ami/dcv_ami.py:
--------------------------------------------------------------------------------
1 | """
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | # this software and associated documentation files (the "Software"), to deal in
5 | # the Software without restriction, including without limitation the rights to
6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | # the Software, and to permit persons to whom the Software is furnished to do so.
8 | #
9 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 | """
16 |
17 | from aws_cdk import (
18 | Stack,
19 | aws_imagebuilder as imagebuilder,
20 | aws_iam as iam,
21 | aws_ec2 as ec2
22 | )
23 | from constructs import Construct
24 |
25 | # The NICE DCV AMI stack
26 | class DcvAmi(Stack):
27 | def __init__(self, scope: Construct, construct_id: str, image_pipeline_name: str,
28 | component_content: str, instance_type: str, config_data: dict, **kwargs) -> None:
29 | super().__init__(scope, construct_id, **kwargs)
30 |
31 | # Component to install for Session Manager or Connection Gateway
32 | component = imagebuilder.CfnComponent(self,
33 | image_pipeline_name,
34 | name=f"{image_pipeline_name}-component",
35 | platform="Linux",
36 | version="1.0.0",
37 | data=component_content
38 | )
39 |
40 | # Recipe that installs all of above components together with a base image
41 | recipe = imagebuilder.CfnImageRecipe(self,
42 | f"{image_pipeline_name}-recipe",
43 | name=f"{image_pipeline_name}-recipe",
44 | version="1.0.0",
45 | components=[
46 | {"componentArn": component.attr_arn},
47 | {"componentArn": "arn:aws:imagebuilder:us-east-1:aws:component/aws-cli-version-2-linux/1.0.4/1"}
48 | ],
49 | parent_image=config_data['sessionMgr']['baseAmiId']
50 | )
51 |
52 | # Distribution to specified accounts and regions
53 | imagebuilder.CfnDistributionConfiguration(self,
54 | f"{image_pipeline_name}-dist-config",
55 | name=f"{image_pipeline_name}-dist-config",
56 | distributions=[{"region": self.region,
57 | "amiDistributionConfiguration": {
58 | "name": image_pipeline_name + "-{{ imagebuilder:buildDate }}",
59 | "description": "NICE DCV AMI",
60 | "targetAccountIds": [ self.account ]
61 | }
62 | }]
63 | )
64 |
65 | # Role for pipeline and instance (ImageBuilder, Logs, and SSM)
66 | role = iam.Role(self, f"{image_pipeline_name}-role",
67 | role_name=f"{image_pipeline_name}-role",
68 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com")
69 | )
70 | role.add_managed_policy(
71 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore")
72 | )
73 | role.add_managed_policy(
74 | iam.ManagedPolicy.from_aws_managed_policy_name("EC2InstanceProfileForImageBuilder")
75 | )
76 |
77 | # Create an instance profile for infrastructure config
78 | instance_profile = iam.CfnInstanceProfile(self,
79 | f"{image_pipeline_name}-instance-profile",
80 | instance_profile_name=f"{image_pipeline_name}-instance-profile",
81 | roles=[role.role_name]
82 | )
83 |
84 | # Select between using the default VPC or use a specific subnet from config.json
85 | if config_data['network']['privateASubnetId'] and config_data['network']['vpcId']:
86 | # Create a reference to the VPC given in the config.json file
87 | vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=config_data['network']['vpcId'])
88 |
89 | # Create an egress only security group for the instance during build ami
90 | security_group = ec2.SecurityGroup(self, "DCVAmiCreationSecurityGroup",
91 | vpc=vpc,
92 | description="SG default ports for DCV",
93 | allow_all_outbound=True, #Egress all
94 | disable_inline_rules=True
95 | )
96 |
97 | # Create infrastructure configuration to supply instance type
98 | infra_config = imagebuilder.CfnInfrastructureConfiguration(self,
99 | f"{image_pipeline_name}-infra-config",
100 | name=f"{image_pipeline_name}-infra-config",
101 | instance_types=[instance_type],
102 | instance_profile_name=instance_profile.instance_profile_name,
103 | subnet_id=config_data['network']['privateASubnetId'],
104 | security_group_ids=[security_group.security_group_id]
105 | )
106 | else: # Use default VPC
107 | # Create infrastructure configuration to supply instance type
108 | infra_config = imagebuilder.CfnInfrastructureConfiguration(self,
109 | f"{image_pipeline_name}-infra-config",
110 | name=f"{image_pipeline_name}-infra-config",
111 | instance_types=[instance_type],
112 | instance_profile_name=instance_profile.instance_profile_name,
113 | )
114 |
115 | # Infrastructure config depends on instance profile to complete before beginning deployment.
116 | instance_profile.add_dependency(role.node.default_child)
117 | infra_config.add_dependency(instance_profile)
118 |
119 | # The imagebuilder pipeline
120 | imagebuilder.CfnImagePipeline(self,
121 | f"{image_pipeline_name}-pipeline",
122 | name=image_pipeline_name,
123 | image_recipe_arn=recipe.attr_arn,
124 | infrastructure_configuration_arn=infra_config.attr_arn
125 | )
126 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/stacks/dcv_infra/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/dcv-samples/62554cb1deb94b843a7faceb94ff774b94f73243/cdk/dcv-gw-sm-with-pipelines/stacks/dcv_infra/__init__.py
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-with-pipelines/stacks/dcv_infra/dcv_infra.py:
--------------------------------------------------------------------------------
1 | """
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | # this software and associated documentation files (the "Software"), to deal in
5 | # the Software without restriction, including without limitation the rights to
6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | # the Software, and to permit persons to whom the Software is furnished to do so.
8 | #
9 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 | """
16 |
17 | import os
18 | from aws_cdk import Stack
19 | import aws_cdk as cdk
20 | import aws_cdk.aws_ec2 as ec2
21 | import aws_cdk.aws_iam as iam
22 | import aws_cdk.aws_kms as kms
23 | import aws_cdk.aws_autoscaling as autoscaling
24 | import aws_cdk.aws_elasticloadbalancingv2 as elbv2
25 | from constructs import Construct
26 |
27 | # The NICE DCV INFRA stack
28 | class DcvInfra(Stack):
29 | """ Class to deploy DCV infrastructure components """
30 | def __init__(self, scope: Construct, construct_id: str, config_data: dict, **kwargs) -> None:
31 | super().__init__(scope, construct_id, **kwargs)
32 |
33 | # Check if a VPC and subnets were provided in the config.json file
34 | if config_data['network']['vpcId'] and config_data['network']['publicASubnetId'] \
35 | and config_data['network']['publicBSubnetId'] \
36 | and config_data['network']['privateASubnetId'] \
37 | and config_data['network']['privateBSubnetId']:
38 | # Create reference for VPC
39 | vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=config_data['network']['vpcId'])
40 | # Create references for private and public subnets
41 | # using subnet_ids pulled from config.json
42 | subnets_public_ref_a = ec2.Subnet.from_subnet_attributes(
43 | self, "PublicSubnetAFromAttributes",
44 | subnet_id=config_data['network']['publicASubnetId'],
45 | availability_zone=f"{self.region}a"
46 | )
47 | subnets_public_ref_b = ec2.Subnet.from_subnet_attributes(
48 | self, "PublicSubnetBFromAttributes",
49 | subnet_id=config_data['network']['publicBSubnetId'],
50 | availability_zone=f"{self.region}b"
51 | )
52 | subnets_private_ref_a = ec2.Subnet.from_subnet_attributes(
53 | self, "PrivateSubnetAFromAttributes",
54 | subnet_id=config_data['network']['privateASubnetId'],
55 | availability_zone=f"{self.region}a"
56 | )
57 | subnets_private_ref_b = ec2.Subnet.from_subnet_attributes(
58 | self, "PrivateSubnetBFromAttributes",
59 | subnet_id=config_data['network']['privateBSubnetId'],
60 | availability_zone=f"{self.region}b"
61 | )
62 | subnets_public = ec2.SubnetSelection(
63 | subnets=[subnets_public_ref_a, subnets_public_ref_b]
64 | )
65 | subnets_private = ec2.SubnetSelection(
66 | subnets=[subnets_private_ref_a, subnets_private_ref_b]
67 | )
68 | else:
69 | # Create new VPC, subnets, and NAT Gateway
70 | vpc = ec2.Vpc(self, "VPC",
71 | nat_gateways = 1,
72 | max_azs = 2,
73 | subnet_configuration=[
74 | ec2.SubnetConfiguration(
75 | name = "public-subnet",
76 | subnet_type = ec2.SubnetType.PUBLIC,
77 | cidr_mask = 24,
78 | ),
79 | ec2.SubnetConfiguration(
80 | name = "private-subnet",
81 | subnet_type = ec2.SubnetType.PRIVATE_WITH_EGRESS,
82 | cidr_mask = 24
83 | )
84 | ],
85 | )
86 | # Create references for private and public subnets
87 | # using availability zones described above
88 | subnets_public = ec2.SubnetSelection(
89 | subnet_type=ec2.SubnetType.PUBLIC
90 | )
91 | subnets_private = ec2.SubnetSelection(
92 | subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS
93 | )
94 |
95 | # IAM Fleet Role Configuration
96 | role_fleet = iam.Role(self, "FleetRole",
97 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
98 | role_name="dcv-fleet-role"
99 | )
100 |
101 | # IAM Session Manager Role Configuration
102 | role_session_mgr = iam.Role(self, "SessionMgrRole",
103 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
104 | role_name="dcv-session-mgr-role"
105 | )
106 |
107 | # IAM Connection Gateway Role Configuration
108 | role_connection_gwy = iam.Role(self, "ConnectionGwyRole",
109 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
110 | role_name="dcv-connection-gwy-role"
111 | )
112 |
113 | # Permission to get DCV License for fleet role
114 | role_fleet.add_to_policy(iam.PolicyStatement(
115 | effect=iam.Effect.ALLOW,
116 | actions=["s3:GetObject"],
117 | resources=[f"arn:aws:s3:::dcv-license.{self.region}/*"]
118 | ))
119 |
120 | role_fleet.add_managed_policy(
121 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore")
122 | )
123 |
124 | iam.CfnInstanceProfile(self, "DCVServerInstanceProfile",
125 | instance_profile_name="dcv-server-profile",
126 | roles=[role_fleet.role_name]
127 | )
128 |
129 | # Permission for Broker Persistence on Session Manager instance
130 | role_session_mgr.add_to_policy(iam.PolicyStatement(
131 | effect=iam.Effect.ALLOW,
132 | actions=[
133 | 'dynamodb:BatchGetItem',
134 | 'dynamodb:BatchWriteItem',
135 | 'dynamodb:ConditionCheckItem',
136 | 'dynamodb:PutItem',
137 | 'dynamodb:DescribeTable',
138 | 'dynamodb:DeleteItem',
139 | 'dynamodb:GetItem',
140 | 'dynamodb:Scan',
141 | 'dynamodb:Query',
142 | 'dynamodb:UpdateItem',
143 | 'dynamodb:CreateTable'
144 | ],
145 | resources=[
146 | f"arn:aws:dynamodb:{self.region}:{self.account}:*",
147 | f"arn:aws:dynamodb:{self.region}:{self.account}:*/*",
148 | f"arn:aws:dynamodb:{self.region}:{self.account}:*/*/index/*"
149 | ]
150 | ))
151 |
152 | # Permission for SSM Parameter for Session Manager instance
153 | role_session_mgr.add_to_policy(iam.PolicyStatement(
154 | effect=iam.Effect.ALLOW,
155 | actions=[
156 | 'ssm:DescribeParameters'
157 | ],
158 | resources=[
159 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/*",
160 | ]
161 | ))
162 |
163 | role_session_mgr.add_to_policy(iam.PolicyStatement(
164 | effect=iam.Effect.ALLOW,
165 | actions=[
166 | 'ssm:PutParameter',
167 | 'ssm:GetParameter'
168 | ],
169 | resources=[
170 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/dcv-broker-private-dns",
171 | ]
172 | ))
173 |
174 | role_session_mgr.add_managed_policy(
175 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore")
176 | )
177 |
178 | # Permission for SSM Parameter for Session Manager instance
179 | role_connection_gwy.add_to_policy(iam.PolicyStatement(
180 | effect=iam.Effect.ALLOW,
181 | actions=[
182 | 'ssm:DescribeParameters'
183 | ],
184 | resources=[
185 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/*",
186 | ]
187 | ))
188 |
189 | # Permission to read the SSM Parameter for Connection Gateway instance
190 | role_connection_gwy.add_to_policy(iam.PolicyStatement(
191 | effect=iam.Effect.ALLOW,
192 | actions=[
193 | 'ssm:GetParameter'
194 | ],
195 | resources=[
196 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/dcv-broker-private-dns"
197 | ]
198 | ))
199 |
200 | role_connection_gwy.add_managed_policy(
201 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore")
202 | )
203 |
204 | # Security Group Configuration
205 | sg_session_mgr = ec2.SecurityGroup(self, "SMSecurityGroup",
206 | vpc=vpc,
207 | description="Default ports for DCV Gateway, DCV Servers and Broker",
208 | allow_all_outbound=True, #Egress all
209 | disable_inline_rules=True
210 | )
211 |
212 | # Add Ingress for DCV TCP/UDP Ports
213 | sg_session_mgr.add_ingress_rule(
214 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8443), "allow CLI to Broker communication"
215 | )
216 | sg_session_mgr.add_ingress_rule(
217 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8445), "allow Agent to Broker communication"
218 | )
219 | sg_session_mgr.add_ingress_rule(
220 | sg_session_mgr, ec2.Port.all_traffic(), "allow Broker to Broker communication"
221 | )
222 |
223 | sg_connection_gwy = ec2.SecurityGroup(self, "CGSecurityGroup",
224 | vpc=vpc,
225 | description="SG default ports for DCV Connection Gateway",
226 | allow_all_outbound=True, #Egress all
227 | disable_inline_rules=True
228 | )
229 |
230 | sg_connection_gwy.add_ingress_rule(
231 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8443), "allow TCP DCV access from public internet"
232 | )
233 | sg_connection_gwy.add_ingress_rule(
234 | ec2.Peer.any_ipv4(), ec2.Port.udp(8443), "allow UDP DCV access from public internet"
235 | )
236 | sg_connection_gwy.add_ingress_rule(
237 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8989), "allow health check for NLB targets"
238 | )
239 |
240 | # Gateway to Session Manager resolver communication
241 | sg_session_mgr.add_ingress_rule(
242 | sg_connection_gwy, ec2.Port.tcp(8447), "allow Gateway to Broker resolver communication"
243 | )
244 |
245 | # DCV server fleet Security Group configuration
246 | sg_dcv_server = ec2.SecurityGroup(self, "DCVServerSecurityGroup",
247 | vpc=vpc,
248 | description="SG default ports for DCV Connection Gateway",
249 | allow_all_outbound=True, #Egress all
250 | disable_inline_rules=True
251 | )
252 |
253 | sg_dcv_server.add_ingress_rule(
254 | sg_connection_gwy, ec2.Port.tcp(8443), "allow DCV streaming traffic from Gateway"
255 | )
256 | sg_dcv_server.add_ingress_rule(
257 | sg_connection_gwy, ec2.Port.udp(8443), "allow DCV streaming traffic from Gateway"
258 | )
259 |
260 | # Get KMS Key from Alias/Key Name
261 | kms_arn = f"arn:aws:kms:{self.region}:{self.account}:alias/{config_data['kmsKeyName']}"
262 | kms_key = kms.Key.from_key_arn(self, "kms-key", kms_arn)
263 |
264 | # Session Manager
265 | ### Session Manager AMI
266 | session_mgr_ami = ec2.GenericLinuxImage({
267 | self.region : config_data['sessionMgr']['builderAmiId']
268 | }
269 | )
270 |
271 | # Add the user data script to custom string
272 | session_mgr_user_data_file = open(os.path.join(os.path.dirname( __file__ ),
273 | "..", "..",
274 | "scripts",
275 | "session-mgr-user-data.sh"),
276 | "r", encoding="utf-8")
277 |
278 | session_mgr_user_data_content = session_mgr_user_data_file.read()
279 | session_mgr_user_data = ec2.UserData.custom(session_mgr_user_data_content)
280 |
281 | # Create a reference to the SSH Key Pair name given in the config.json file
282 | key_pair = ec2.KeyPair.from_key_pair_attributes(self, "DCVKeyPair",
283 | key_pair_name=config_data['sshKeypairName']
284 | )
285 |
286 | # Create the Session Manager EC2 instance
287 | session_mgr_instance = ec2.Instance(self, "SessionMgrInstance",
288 | vpc=vpc,
289 | vpc_subnets=subnets_private,
290 | instance_type=ec2.InstanceType.of(
291 | ec2.InstanceClass.M6G, ec2.InstanceSize.LARGE),
292 | machine_image=session_mgr_ami,
293 | security_group=sg_session_mgr,
294 | key_pair=key_pair,
295 | user_data=session_mgr_user_data,
296 | role=role_session_mgr,
297 | block_devices=[ec2.BlockDevice(
298 | device_name="/dev/xvda",
299 | volume=ec2.BlockDeviceVolume.ebs(
300 | 8, encrypted=True, kms_key=kms_key))]
301 | )
302 |
303 | # Connection Gateway
304 | ### Connection Gateway AMI
305 | connection_gwy_ami = ec2.GenericLinuxImage({
306 | self.region : config_data['connectionGwy']['builderAmiId']
307 | })
308 |
309 | # Add the user data script to custom string
310 | connection_gwy_user_data_file = open(os.path.join(os.path.dirname( __file__ ),
311 | "..", "..",
312 | "scripts",
313 | "connection-gwy-user-data.sh"),
314 | "r", encoding="utf-8")
315 |
316 | connection_gwy_user_data_content = connection_gwy_user_data_file.read()
317 | connection_gwy_session_mgr_user_data = ec2.UserData.custom(connection_gwy_user_data_content)
318 |
319 | # Create an EC2 launch template with the encrypted volume for Connection Gateway
320 | connection_gwy_launch_template = ec2.LaunchTemplate(self, "ConnectionGwyLaunchTemplate",
321 | machine_image=connection_gwy_ami,
322 | security_group=sg_connection_gwy,
323 | instance_type=ec2.InstanceType.of(
324 | ec2.InstanceClass.C7G, ec2.InstanceSize.LARGE),
325 | key_pair=key_pair,
326 | user_data=connection_gwy_session_mgr_user_data,
327 | role=role_connection_gwy,
328 | block_devices=[ec2.BlockDevice(
329 | device_name="/dev/xvda",
330 | volume=ec2.BlockDeviceVolume.ebs(
331 | 8, encrypted=True, kms_key=kms_key))],
332 | )
333 |
334 | # Create a Connection Gateway Auto Scaling Group
335 | connection_gwy_asg = autoscaling.AutoScalingGroup(self, "ConnectionGwyASG",
336 | vpc=vpc,
337 | launch_template=connection_gwy_launch_template,
338 | min_capacity=1,
339 | max_capacity=5,
340 | desired_capacity=1,
341 | vpc_subnets=subnets_private
342 | )
343 |
344 | # Ensure Session Manager instance is created before Connection Gateway targets
345 | connection_gwy_asg.node.add_dependency(session_mgr_instance)
346 |
347 | # Connection Gateway Auto Scaling Group CPU Utilization to scale
348 | connection_gwy_asg.scale_on_cpu_utilization(
349 | "ConnectionGwyASGCPUUtilization", target_utilization_percent=75
350 | )
351 |
352 | # Create a Connection Gateway Network Load Balancer
353 | connection_gwy_nlb = elbv2.NetworkLoadBalancer(self, "ConnectionGwyNLB",
354 | vpc=vpc,
355 | internet_facing=True,
356 | vpc_subnets=subnets_public,
357 | load_balancer_name="connection-gwy-nlb",
358 | cross_zone_enabled=True
359 | )
360 |
361 | # Connection Gateway Listener to Target Setup for NLB
362 | connection_gwy_listener = connection_gwy_nlb.add_listener(
363 | "ConnectionGwyNLBListener", port=8443, protocol=elbv2.Protocol.TCP_UDP
364 | )
365 |
366 | # Route the Connection Gateway targets
367 | connection_gwy_listener.add_targets("ConnectionGwyNLBTarget",
368 | port=8443,
369 | protocol=elbv2.Protocol.TCP_UDP,
370 | health_check=elbv2.HealthCheck(
371 | port="8989",
372 | protocol=elbv2.Protocol.TCP,
373 | unhealthy_threshold_count=5,
374 | healthy_threshold_count=5,
375 | interval=cdk.Duration.seconds(30)
376 | ),
377 | targets=[connection_gwy_asg]
378 | )
379 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/README.md:
--------------------------------------------------------------------------------
1 | # Deployment of Amazon DCV Connection Gateway and DCV Sessions Manager broker
2 |
3 | Accelerate cloud deployment of foundational autoscaling infrastructure for [Amazon DCV](https://aws.amazon.com/hpc/dcv/) with AWS Cloud Development Kit (AWS CDK).
4 |
5 | ## Overview
6 | The architecture diagram below illustrates the resources that this sample deploys into your account. This CDK deploys a single DCV Session Manager, a DCV Connection Gateway Auto Scaling group, an AWS Network Load Balancer forwarding traffic to the gateways, the required IAM roles for the architecture (gateway, broker, and DCV server), and configured Security Groups. The CDK provides the choice of deploying in an existing VPC or creating a new one.
7 | >Note: A DCV server fleet is not automatically deployed with this CDK. Instructions for deploying your DCV server fleet are within **Step 17: Testing Your Configuration**.
8 |
9 | 
10 |
11 |
12 | Figure 1: AWS CDK that will setup the foundational infrastructure for a scale out solution of Amazon DCV Connection Gateway and Session Manager.
13 |
14 | ## Prerequisites
15 | - An AWS account with full permissions on:
16 | - AWS Systems Manager (AWS SSM) Parameter Store
17 | - AWS SSM Session Manager
18 | - Amazon Elastic Compute Cloud (Amazon EC2)
19 | - Amazon Virtual Private Cloud (Amazon VPC)
20 | - A system with the following installed:
21 | - AWS Command Line Interface (AWS CLI)
22 | - AWS CDK
23 | - Node.js
24 | - Python
25 | - Git
26 | - Basic understanding of:
27 | - AWS Cloud
28 | - Scripting languages (Python, Bash)
29 | - DCV
30 |
31 | # AWS VPC Infrastructure Creation with CDK
32 | This example contains:
33 | - Choice of VPC and Subnets
34 | - If you do not specify a VPC, the CDK will create:
35 | - A new VPC with an Internet Gateway
36 | - Public and Private subnets
37 | - Two availability zones
38 | - NAT Gateway
39 | - A security groups for DCV Connection Gateway, DCV Session Manager, and DCV Server
40 | - IAM roles required for configuration
41 | - Network Load Balancer for DCV Connection Gateway
42 | - Autoscaling Groups for the DCV Connection Gateway instances
43 | - This solution will initialize the autoscaling group with one Connection Gateway instance per availability zone
44 | - Autoscaling based off of CPU consumption
45 | - SSM Parameter Store parameter to hold the broker DNS
46 |
47 | >Note: An SSH key-pair (.pem or .ppk) is required to be registered in your AWS account and region. This key-pair name is required within the `config.json` file before deploying the infrastructure stack in order to allow SSH access into the instances. AWS SSM can also be used for terminal access.
48 |
49 | ## Step 1: NPM
50 | The LTS version of [npm](https://www.npmjs.com/) is recommended. If npm is already on your system, upgrade npm to the latest version.
51 | npm install -g npm@latest
52 |
53 | ```bash
54 | npm install -g npm@latest
55 | ```
56 |
57 | ## Step 2: AWS CDK
58 |
59 | Ensure that the latest [aws-cdk](https://aws.amazon.com/cdk/) is installed.
60 |
61 | ```bash
62 | npm install -g aws-cdk
63 | ```
64 |
65 | Once installed, the command cdk --version will confirm installation was successful.
66 |
67 | ```bash
68 | cdk --version
69 | ```
70 |
71 | ## Step 3: AWS CLI
72 | Install [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
73 |
74 |
75 | ## Step 4: Git
76 | Install [Git](https://git-scm.com/)
77 |
78 | ## Step 5: Clone the Repository
79 | Visit [clone a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) for instructions. Clone this repository locally.
80 |
81 | ## Step 6: Create a virtual environment
82 | Open up a command line terminal of your choice. Change directory into the cloned repository.
83 | ### Windows
84 | ```bash
85 | virtualenv --python dcv-env
86 | .\dcv-env\Scripts\activate
87 | ```
88 | ### macOS/Linux
89 | ```bash
90 | virtualenv --python dcv-env
91 | source dcv-env/bin/activate
92 | ```
93 |
94 | ## Step 7: Install Project Dependencies
95 | Install project dependencies by running the following command.
96 |
97 | ```bash
98 | pip install -r requirements.txt
99 | ```
100 |
101 | ## Step 8: Assume IAM role
102 | [Use an IAM role in the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html).
103 | > Note: To confirm your credentials are associated with the correct AWS account, you can run the following AWS CLI command -
104 | ```bash
105 | aws sts get-caller-identity
106 | ```
107 | (See [get-caller-identity](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/get-caller-identity.html) in the AWS CLI documentation).
108 |
109 | ## Step 9: CDK Bootstrap
110 | [Bootstrap your AWS CDK environment. ](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-bootstrap)
111 | Replace with your desired account number and region.
112 | ```bash
113 | cdk bootstrap 111122223333/us-east-1
114 | ```
115 |
116 | ## Step 10: Set AWS Account and Region for Infrastructure
117 | Set the AWS account id and region by specifying in `/config.json`
118 | ```json
119 | {
120 | ...
121 | "accountId": "xxxxxxxxxxxx",
122 | "region": "xxxxxxxxxxxxxxx",
123 | ...
124 | }
125 | ```
126 | Also, be sure the region is set in your AWS credentials by running the following command by replacing `us-east-1` with your intended region:
127 |
128 | For Windows:
129 | ```powershell
130 | set AWS_REGION=us-east-1
131 | ```
132 | For Mac/Linux:
133 | ```bash
134 | export AWS_REGION=us-east-1
135 | ```
136 |
137 | ## Step 11: Check Project with Synth
138 | Verify there are no errors with the cloned project with [cdk synth](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-synth) (synthesize).
139 | ```bash
140 | cdk synth --all
141 | ```
142 |
143 | ## Step 12: Config Network Settings
144 | If you do not provide a VPC and subnets within *config.json*, the CDK will create a new VPC.
145 |
146 | **Provisioning**
147 | - Network Load Balancer provisioned across public subnets
148 | - DCV Connection Gateway Auto Scaling group provisioned across private subnets
149 | - A single DCV Session Manager host provisioned in private subnet
150 |
151 | **Note:** The subnets assume you are targeting A and B Availability Zones (AZ). For example, ```publicASubnetId``` is aligned to the *region-a* AZ. If you would like to change your AZ, you can update the static assignments in *dcv_infra.py*.
152 |
153 | ```json
154 | "network" : {
155 | "vpcId": "",
156 | "publicASubnetId": "",
157 | "publicBSubnetId": "",
158 | "privateASubnetId": "",
159 | "privateBSubnetId": ""
160 | } ...
161 | ```
162 |
163 |
164 | ## Step 13: Add AMI IDs into the CDK project
165 |
166 | This CDK will bootstrap the provided AMIs to install the required components. For more information, see the **AMI Checklist** below.
167 |
168 | ### AMI Checklist
169 | - Provide AMI IDs that are based on supported operating systems for [DCV Session Manager broker](https://docs.aws.amazon.com/dcv/latest/sm-admin/requirements.html) and [DCV Connection Gateway](https://docs.aws.amazon.com/dcv/latest/gw-admin/system-requirements.html).
170 | - Ensure your provided AMI is up to date and has the [AWS CLI](https://aws.amazon.com/cli/) installed.
171 | - The CDK assumes you are using ARM-based AMIs so you can benefit from [EC2 Graviton](https://aws.amazon.com/ec2/graviton/). If you would like to use an x86-based AMI, you may update the statically configured instance types in *dcv_infra.py*.
172 | - If you do not have an AMI to provide, use the latest ARM-based Amazon Linux 2 AMI in your target region.
173 | - The procedure in this README will use AWS Systems Manager Session Manager for access. To follow this procedure, ensure [SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) is installed on your AMI.
174 |
175 | ```json
176 | {
177 | ...
178 | "sessionMgr" : {
179 | "baseAmiId": "ami-xxxxxxxxxxxxxxxxx"
180 | },
181 | "connectionGwy" : {
182 | "baseAmiId": "ami-xxxxxxxxxxxxxxxxx"
183 | }
184 | }
185 | ```
186 |
187 |
188 | ## Step 14: Key Pairs for EC2
189 | Use your own Key Pair or [Create Key Pairs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-key-pairs.html) for accessing the EC2s.
190 |
191 | Use the Key Pair value for ssh_keypair_name in `/config.json`
192 | ```json
193 | {
194 | ...
195 | "sshKeypairName": "xxxxxxxxxxxxxxx",
196 | ...
197 | }
198 | ```
199 |
200 | ## Step 15: AWS Key Management Service (KMS)
201 | Choose to use the AWS provide default KMS or [Create Keys](href="https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html).
202 |
203 | Use the KMS value for kms_key_name in `/config.json`
204 |
205 | ```json
206 | {
207 | ...
208 | "kmsKeyName": "aws/ebs",
209 | ...
210 | }
211 | ```
212 |
213 | ## Step 16: Deploy Infrastructure stack
214 | ```bash
215 | cdk deploy
216 | ```
217 |
218 | ## Step 17: Testing Your Configuration
219 | Now that your infrastructure is created, you must create a DCV session on a DCV server to connect to. For this step, [DCV Session Manager CLI](https://docs.aws.amazon.com/dcv/latest/sm-cli/sm-cli-reference.html) is required, as well as a [DCV Server](https://docs.aws.amazon.com/dcv/latest/adminguide/servers.html). Alteratively, you may deploy DCV Access Console. Use the instructions below to test your deployment.
220 |
221 | ### Testing Prerequisites
222 | There are several ways testing can be performed, but this guide uses [AWS Systems Manager Session Manager](https://aws.amazon.com/systems-manager/) and the CDK provides IAM permissions to use it.
223 |
224 | ### Launch a DCV Server Fleet Instance
225 | Once your CDK deployed instances are passing EC2 health checks, a DCV fleet server is required to be launched. The DCV server also needs to have the DCV Session Manager agent installed. With both of these components configured, the instance will check in with the DCV Session Manager broker so sessions on the instance can be managed by the broker.
226 |
227 | **Note:** You will need to manage the user accounts on the DCV servers. If you do not have a centralized identity (e.g. Microsoft Active Directory), you need to create a local user and set a password. The default user for Windows is `Administrator` and the default user for Amazon Linux 2 is `ec2-user`. You can create new users or update passwords by using AWS Systems Manager Session Manager for remote access.
228 |
229 | #### Windows
230 | To bootstrap a Windows DCV server, first download the [Install-DCVandSMAgent.ps1](/bootstrap/Install-DCVandSMAgent.ps1) script from the bootstrap folder of dcv-samples. Once downloaded, update the `SESSION-MGR-PRIVATE-DNS` placeholder with the private DNS name of your DCV Session Manager instance. This can be retrieved from the EC2 console. Deploy a new Windows-based instance within a private subnet and inject the script content in the **User data** field. Ensure you have chosen a base image that is [supported by DCV server](https://docs.aws.amazon.com/dcv/latest/adminguide/servers.html). The CDK provisioned a DCV server security group named `DcvInfraStack-DCVServerSecurityGroup*`. The CDK also created an instance profile named `dcv-fleet-role`.
231 |
232 | #### Linux
233 | To bootstrap a Windows DCV server, first download the [linux-config-sessionmgr-agent.sh](/bootstrap/linux-config-sessionmgr-agent.sh) script from the bootstrap folder of dcv-samples. Once downloaded, update the `SESSION-MGR-PRIVATE-DNS` placeholder with the private DNS name of your DCV Session Manager instance. This can be retrieved from the EC2 console. By default, Linux operating systems do not provide a desktop environment. For simplicity, you may use the [AWS Marketplace DCV AMI for Amazon Linux 2](https://aws.amazon.com/marketplace/seller-profile?id=74eff437-1315-4130-8b04-27da3fa01de1). Deploy a new instance based on the Marketplace AMI within a private subnet and inject the script content in the **User data** field. If you use an alternative image, ensure you have chosen a base image that is [supported by DCV server](https://docs.aws.amazon.com/dcv/latest/adminguide/servers.html). The CDK provisioned a DCV server security group named `DcvInfraStack-DCVServerSecurityGroup*`. The CDK also created an instance profile named `dcv-fleet-role`.
234 |
235 | When your newly deployed instance is passing EC2 health checks, proceed to the next step.
236 |
237 | ### Register an API Client on Session Manager Instance
238 | 1. Access your DCV Session Manager instance using Systems Manager Session Manager.
239 | 2. To make API calls to your broker, you will need to [register an API client](https://docs.aws.amazon.com/dcv/latest/sm-admin/register-api-client.html). To generate these credentials, run the following command.
240 | > IMPORTANT: These credentials cannot be retrieved later so take note of the response. You will need to rerun this command if you lose the credentials.
241 |
242 | ```bash
243 | sudo -u root dcv-session-manager-broker register-api-client --client-name client_name
244 | ```
245 | 3. Record the printed credentials and exit out of Sessions Manager SSH session
246 |
247 | ### Communicating with the broker
248 |
249 | #### Option 1: Deploy the DCV Access Console
250 | The [DCV Access Console](https://docs.aws.amazon.com/dcv/latest/access-console/what-is-access-console.html) is a web application that helps administrators and end users manage their DCV sessions. To deploy the DCV Access Console, see the [CDK README]() or [administrator guide](https://docs.aws.amazon.com/dcv/latest/access-console/setup.html).
251 |
252 | #### Option 2: Download and Configure the DCV Session Manager CLI
253 | The [DCV Session Manager Command Line Interface (CLI)](https://docs.aws.amazon.com/dcv/latest/sm-cli/what-is-sm-cli.html) is used to interact with a DCV Session Manager broker using commands in your command-line shell. The CDK allows access from the DCV Connection Gateway instances. Alternatively, you may run the CLI on the Session Manager instance.
254 |
255 | 1. Download the DCV Session Manager CLI with the following command:
256 | ```bash
257 | wget https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-session-manager-cli.zip
258 | ```
259 |
260 | 2. Unzip the CLI package with the following command:
261 | ```bash
262 | unzip nice-dcv-session-manager-cli.zip
263 | ```
264 |
265 | 3. Configure the CLI ```dcvsmcli.conf``` file. See the [CLI guide](https://docs.aws.amazon.com/dcv/latest/sm-cli/configuration-file.html) for a reference. You will need to have the following configuration set.
266 | ```bash
267 |
268 | [output]
269 | # The formatting style for command output.
270 | output-format = json
271 |
272 | # Turn on debug logging
273 | #debug = true
274 |
275 | [security]
276 | # Disable SSL certificates verification.
277 | no-verify-ssl = true
278 |
279 | # CA certificate bundle to use when verifying SSL certificates.
280 | #ca-bundle = ca-bundle.pem
281 |
282 | [authentication]
283 | # hostname of the authentication server used to request the token
284 | #auth-server-url = https://broker-host:broker-port/oauth2/token?grant_type=client_credentials
285 |
286 | # The client ID
287 | client-id = CLIENT_ID_FROM_REGISTRATION
288 |
289 | # The client password
290 | client-password = CLIENT_PASSWORD_FROM_REGISTRATION
291 |
292 | [broker]
293 | # hostname or IP of the broker
294 | url = https://DNSorIP-DCVSessionMgr:8443
295 |
296 | ```
297 |
298 | 4. Test your CLI install and ensure the DCV server is checked in with the broker by running the following command. This should return the DCV Fleet instance. Run the following commands from within the CLI unzipped folder.
299 | ```bash
300 | python3 dcvsm describe-servers
301 | ```
302 | - Output should return an available server in the JSON
303 | - If no servers are available, follow the **Troubleshooting DCV Fleet Session Manager Creation Errors** section below.
304 |
305 | 5. Run the following command to have DCV Session Manager create a DCV session on the DCV Server you deployed. Take note of the `"successful_list": "id"` (*not* `request_id`) in the call response.
306 | >Note: Be sure to enter the fleet instance ID in the `requirements` argument. For additional requirements, see [DCV Session Manager Developer Guide](https://docs.aws.amazon.com/dcv/latest/sm-dev/CreateSessions.html#request). The placeholder *LOCALUSER* should be replaced with the user on the instance you plan to login with.
307 |
308 | ```bash
309 | python3 dcvsm create-session --name Testing --owner LOCALUSER --type Console --requirements "server:Host.Aws.Ec2InstanceId = 'i-XXXXXXXXXXXXXXXXX'"
310 | ```
311 | 6. Run the following command to retrieve the DCV session’s authentication token specific to the connecting user. Take note of the token in the response.
312 | >Note: Be sure to enter the `session-id` below from the previous step.
313 | ```bash
314 | python3 dcvsm get-session-connection-data --session-id --user LOCALUSER
315 | ```
316 | - Take note the `connection_token` in the response.
317 | 7. You can initiate a connection from a DCV client using the session ID and authentication code. The [connection string](https://docs.aws.amazon.com/dcv/latest/sm-dev/GetSessionConnectionData.html#additional-info) should be formatted as:
318 | - `Connection-Gateway-NLB-DNSorIP:8443/?authToken=TOKEN#SESSION-ID`
319 | - Replace `TOKEN` with the `connection_token` retrieved from the previous call.
320 | - Replace `SESSION-ID` with the session ID returned when you created the session.
321 | - **Note:** you must initiate the call from a [DCV client](https://docs.aws.amazon.com/dcv/latest/userguide/client.html).
322 | 8. Once your connection is established, log in to your DCV Fleet Server with the instance credentials.
323 |
324 | ## Cleanup Your Environment
325 | To destroy all infrastructure contained in the CDK, run the following command:
326 | - Be sure to terminate and remove bastion resources manually created (e.g. instances, security groups, etc.) that were used in testing (any infrastructure outside of the CDK project, but within the VPC) before running the command below.
327 | - You will need to delete the SSM Parameter for the broker private ip named `dcv-broker-private-ip-*`.
328 | ```bash
329 | # Destroy all project resources.
330 | cdk destroy
331 | ```
332 |
333 | ## Troubleshooting DCV Fleet Session Manager Creation Errors
334 | 1. List all sessions. Output should be a list of DCV sessions.
335 | ```bash
336 | python3 dcvsm describe-sessions
337 | ```
338 | 2. Check the CLI can find DCV servers. Output should be an available server in the JSON.
339 | ```bash
340 | python3 dcvsm describe-servers
341 | ```
342 | 3. Check the Agent is running. Output should be "Success".
343 | ```bash
344 | grep 'sessionsUpdateResponse' /var/log/dcv-session-manager-agent/agent.log | tail -1 | grep -o success`
345 | ```
346 | 4. Check the Broker is running. Output should be { "error": "No authorization header"}
347 | >Note: Be sure to fill in the correct private IP address and region from the Session Manager instance below in `X-X-X-X.xx-xxxx-x`. (e.g. `10-0-2-63.us-west-2`)
348 | ```bash
349 | curl -X GET https://BROKER_DNS:8443/sessionConnectionData/aSession/aOwner --insecure
350 | ```
351 | For more information, see the *Verify the installations* page of the [DCV Session Manager Administrator guide](https://docs.aws.amazon.com/dcv/latest/sm-admin/verify.html).
352 |
353 | ## Authors and acknowledgment
354 | [Andrew Morgan](https://github.com/morgnza)
355 | [Eric Cornwell](https://github.com/Eecornwell)
356 |
357 | ## License
358 | MIT License
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/app.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | # this software and associated documentation files (the "Software"), to deal in
5 | # the Software without restriction, including without limitation the rights to
6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | # the Software, and to permit persons to whom the Software is furnished to do so.
8 | #
9 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import json
17 | import aws_cdk as cdk
18 | from stacks.dcv_infra.dcv_infra import DcvInfra
19 |
20 | app = cdk.App()
21 |
22 | # Load the app configuration from the config.json file
23 | try:
24 | with open("config.json", "r") as config_file:
25 | config_data = json.load(config_file)
26 | except Exception as e:
27 | print(f"Could not read the app configuration file. {e}")
28 | raise e
29 |
30 |
31 | # Set CDK environment variables
32 | environment = cdk.Environment(account=config_data['accountId'], region=config_data['region'])
33 |
34 | # Create the DCV Infrastructure Stack for Session Manager and Connection Gateway
35 | DcvInfra(app, "DcvInfraStack",
36 | description='(uksb-1tupboc66) (tag:dcv-gw-sm-without-pipelines)',
37 | config_data=config_data,
38 | env=environment)
39 |
40 | app.synth()
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/cdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": "python app.py",
3 | "watch": {
4 | "include": [
5 | "**"
6 | ],
7 | "exclude": [
8 | "README.md",
9 | "cdk*.json",
10 | "requirements*.txt",
11 | "**/__init__.py",
12 | "**/__pycache__"
13 | ]
14 | },
15 | "context": {
16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
17 | "@aws-cdk/core:checkSecretUsage": true,
18 | "@aws-cdk/core:target-partitions": [
19 | "aws",
20 | "aws-cn"
21 | ],
22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
25 | "@aws-cdk/aws-iam:minimizePolicies": true,
26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
31 | "@aws-cdk/core:enablePartitionLiterals": true,
32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
33 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true,
34 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
35 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
36 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
37 | "@aws-cdk/aws-route53-patters:useCertificate": true,
38 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false,
39 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
40 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
41 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
42 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
43 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
44 | "@aws-cdk/aws-redshift:columnId": true,
45 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
46 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
47 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
48 | "@aws-cdk/aws-kms:aliasNameRef": true,
49 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
50 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
51 | "@aws-cdk/aws-efs:denyAnonymousAccess": true,
52 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
53 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
54 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
55 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
56 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
57 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
58 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "comment": "NOTE: BEFORE DEPLOYING SESSION MANAGER AND CONNECTION GATEWAY STACK, UPDATE THE ACCOUNT ID AND REGION BELOW",
3 | "accountId": "xxxxxxxxxxxx",
4 | "region": "xx-xxxx-x",
5 | "sshKeypairName": "",
6 | "kmsKeyName": "aws/ebs",
7 | "network" : {
8 | "vpcId": "",
9 | "publicASubnetId": "",
10 | "publicBSubnetId": "",
11 | "privateASubnetId": "",
12 | "privateBSubnetId": ""
13 | },
14 | "sessionMgr" : {
15 | "baseAmiId": "ami-xxxxxxxxxxxxxxxxx"
16 | },
17 | "connectionGwy" : {
18 | "baseAmiId": "ami-xxxxxxxxxxxxxxxxx"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/documentation/images/SolutionArchitecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/dcv-samples/62554cb1deb94b843a7faceb94ff774b94f73243/cdk/dcv-gw-sm-without-pipelines/documentation/images/SolutionArchitecture.png
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/requirements.txt:
--------------------------------------------------------------------------------
1 | aws-cdk-lib>=2.141.0
2 | constructs>=10.0.0,<11.0.0
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/scripts/connection-gwy-user-data.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | # this software and associated documentation files (the "Software"), to deal in
6 | # the Software without restriction, including without limitation the rights to
7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | # the Software, and to permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
12 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
14 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | LOG_PATH="/var/log/dcv-connection-gwy-install.log"
18 | echo $(date -u) "*****START USER DATA SCRIPT*****" | tee -a "$LOG_PATH"
19 |
20 | # Retrieve System Info
21 | echo $(date -u) "Discovering OS Info" | tee -a "$LOG_PATH"
22 | read -r system version <<<$(echo $(cat /etc/os-release | grep "^ID=\|^VERSION_ID=" | sort | cut -d"=" -f2 | tr -d "\"" | tr '[:upper:]' '[:lower:]'))
23 | major_version="${version%.*}"
24 | arch="$(arch)"
25 | CLOUDFRONT_PREFIX="https://d1uj6qtbmh3dt5.cloudfront.net"
26 | TMP_DIR="$(mktemp -d /tmp/XXXXXX)"
27 | trap 'rm -rf -- "$TMP_DIR"' ERR
28 |
29 | case $system in
30 | amzn )
31 | if [ "$major_version" = 2 ]; then
32 | package_type="el7"
33 | package_manager="yum"
34 | package_extension="rpm"
35 | fi
36 | ;;
37 | centos|rhel )
38 | if [[ "$major_version" =~ ^(7|8|9) ]]; then
39 | package_type="el$major_version"
40 | if [[ "$major_version" =~ ^(8|9) ]]; then
41 | package_manager="dnf"
42 | else
43 | package_manager="yum"
44 | fi
45 | package_extension="rpm"
46 | fi
47 | ;;
48 | ubuntu )
49 | if [ "$major_version" = 22 ] || [ "$major_version" = 20 ]; then
50 | package_type="ubuntu$(echo $version | tr -d '.')"
51 | package_manager="apt"
52 | package_extension="deb"
53 | fi
54 | ;;
55 | * )
56 | echo "Error: system '$system' is not supported"
57 | exit 1
58 | ;;
59 | esac
60 |
61 | if [ -z "$package_type" ]; then
62 | echo "Error: system '$system' with version '$version' is not supported for arch '$arch'"
63 | exit 1
64 | fi
65 | echo $(date -u) "Discovered OS:" | tee -a "$LOG_PATH"
66 | echo $(date -u) "Arch: $arch" | tee -a "$LOG_PATH"
67 | echo $(date -u) "OS Type: $package_type" | tee -a "$LOG_PATH"
68 | echo $(date -u) "Package Manager: $package_manager" | tee -a "$LOG_PATH"
69 | echo $(date -u) "Package Extension: $package_extension" | tee -a "$LOG_PATH"
70 |
71 | # Download Packages
72 | echo $(date -u) "Downloading DCV Connection Gateway Packages" | tee -a "$LOG_PATH"
73 | if [ "$package_manager" = apt ]; then
74 | curl -o "$TMP_DIR/NICE-GPG-KEY" "$CLOUDFRONT_PREFIX/NICE-GPG-KEY"
75 | gpg --import "$TMP_DIR/NICE-GPG-KEY"
76 | if [ $arch != "x86_64" ]; then
77 | deb_arch="arm64"
78 | curl -o "$TMP_DIR/nice-dcv-server.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-ubuntu2204-aarch64.tgz"
79 | else
80 | deb_arch="amd64"
81 | curl -o "$TMP_DIR/nice-dcv-server.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-$package_type-$arch.tgz"
82 | fi
83 | curl -o "$TMP_DIR/nice-dcv-connection-gateway.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-connection-gateway_$deb_arch.$package_type.$package_extension"
84 | else
85 | rpm --import "$CLOUDFRONT_PREFIX"/NICE-GPG-KEY
86 | curl -o "$TMP_DIR/nice-dcv-connection-gateway.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-connection-gateway-$package_type.$arch.$package_extension"
87 | curl -o "$TMP_DIR/nice-dcv-server.tgz" "$CLOUDFRONT_PREFIX/nice-dcv-$package_type-$arch.tgz"
88 | fi
89 |
90 | # Install Packages
91 | echo $(date -u) "Installing DCV Connection Gateway" | tee -a "$LOG_PATH"
92 | tar -xvzf "$TMP_DIR/nice-dcv-server.tgz" -C "$TMP_DIR"
93 | for package_pattern in "nice-dcv-web-viewer*" "nice-dcv-connection-gateway.$package_extension"; do
94 | package_full_path=$(find "$TMP_DIR" -name "$package_pattern")
95 | "$package_manager" install -y "$package_full_path"
96 | done
97 |
98 | # Enables Web Access through the Gateway
99 | sed -i --expression 's|url = "https://localhost:8080"|local-resources-path = "/usr/share/dcv/www"|' /etc/dcv-connection-gateway/dcv-connection-gateway.conf
100 |
101 | # Enable and start Gateway
102 | systemctl enable dcv-connection-gateway
103 | systemctl start dcv-connection-gateway
104 |
105 | # Clean Up
106 | rm -rf "$TMP_DIR"
107 |
108 | # Get current region
109 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
110 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
111 | echo $(date -u) "Current Region: $REGION" | tee -a "$LOG_PATH"
112 |
113 | # Retrieve Broker Private DNS from SSM Parameter Store
114 | echo $(date -u) "Retrieving broker private DNS from SSM Parameter Store" | tee -a "$LOG_PATH"
115 | BROKER_PRIVATE_DNS=$(aws ssm get-parameter --name dcv-broker-private-dns --region "$REGION" --with-decryption | grep -Po '"Value": "\K[^"]*')
116 | timeout 1 bash -c "/dev/tcp/$BROKER_PRIVATE_DNS/8447"
117 | RESPONSE="$?"
118 | while [ "$RESPONSE" != 0 ]; do
119 | echo $(date -u) "Unable to reach broker. Waiting before retry." | tee -a "$LOG_PATH"
120 | sleep 15s
121 | BROKER_PRIVATE_DNS=$(aws ssm get-parameter --name dcv-broker-private-dns --region "$REGION" --with-decryption | grep -Po '"Value": "\K[^"]*')
122 | timeout 1 bash -c "cat < /dev/null > /dev/tcp/$BROKER_PRIVATE_DNS/8447"
123 | RESPONSE="$?"
124 | done
125 | echo $(date -u) "Broker private DNS found $BROKER_PRIVATE_DNS" | tee -a "$LOG_PATH"
126 |
127 | # Port Configuration. Using hex to escape double quotes: \x22 = "
128 | echo $(date -u) "Configuring Connection Gateway..." | tee -a "$LOG_PATH"
129 | sed -i "s/^#\[health-check\]/\[health-check\]/g" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
130 | sed -i --expression 's|#bind-addr = "::"|bind-addr = "::"|' /etc/dcv-connection-gateway/dcv-connection-gateway.conf
131 | sed -i --expression 's|#tls-strict = false|tls-strict = false|' /etc/dcv-connection-gateway/dcv-connection-gateway.conf
132 | sed -i "/\[resolver\]/a tls-strict = false" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
133 | sed -i "/bind-addr = \"::\"/a port = 8989" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
134 | sed -i "s|url = \"https://localhost:8081\"|url = \"https://$BROKER_PRIVATE_DNS:8447\"|" /etc/dcv-connection-gateway/dcv-connection-gateway.conf
135 |
136 | # Start DCV Connection Gateway Service
137 | echo $(date -u) "Starting and Enabling Connection Gateway service..." | tee -a "$LOG_PATH"
138 | systemctl restart dcv-connection-gateway.service
139 |
140 | # Log if successful installation
141 | if [[ $? -eq 0 ]]; then
142 | echo $(date -u) "Successfully installed DCV Connection Gateway" | tee -a "$LOG_PATH"
143 | else
144 | echo $(date -u) "There was an error during DCV Connection Gateway installation" | tee -a "$LOG_PATH"
145 | fi
146 |
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/scripts/session-mgr-user-data.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | # this software and associated documentation files (the "Software"), to deal in
6 | # the Software without restriction, including without limitation the rights to
7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | # the Software, and to permit persons to whom the Software is furnished to do so.
9 | #
10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
12 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
14 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | set -eE
18 | LOG_PATH="/var/log/dcv-session-mgr-install.log"
19 | echo $(date -u) "*****START USER DATA SCRIPT*****" | tee -a $LOG_PATH
20 |
21 | # Retrieve System Info
22 | read -r system version <<<$(echo $(cat /etc/os-release | grep "^ID=\|^VERSION_ID=" | sort | cut -d"=" -f2 | tr -d "\"" | tr '[:upper:]' '[:lower:]'))
23 | major_version="${version%.*}"
24 | CLOUDFRONT_PREFIX="https://d1uj6qtbmh3dt5.cloudfront.net"
25 | TMP_DIR="$(mktemp -d /tmp/XXXXXX)"
26 | trap 'rm -rf -- "$TMP_DIR"' ERR
27 |
28 | case $system in
29 | amzn )
30 | if [ "$major_version" = 2 ]; then
31 | package_type="el7"
32 | package_manager="yum"
33 | package_extension="rpm"
34 | fi
35 | ;;
36 | centos|rhel )
37 | if [[ "$major_version" =~ ^(7|8|9) ]]; then
38 | package_type="el$major_version"
39 | if [[ "$major_version" =~ ^(8|9) ]]; then
40 | package_manager="dnf"
41 | else
42 | package_manager="yum"
43 | fi
44 | package_extension="rpm"
45 | fi
46 | ;;
47 | ubuntu )
48 | if [ "$major_version" = 22 ] || [ "$major_version" = 20 ]; then
49 | package_type="ubuntu$(echo $version | tr -d '.')"
50 | package_manager="apt"
51 | package_extension="deb"
52 | fi
53 | ;;
54 | * )
55 | echo "Error: system '$system' is not supported"
56 | exit 1
57 | ;;
58 | esac
59 |
60 |
61 | if [ -z "$package_type" ]; then
62 | echo "Error: system '$system' with version '$version' is not supported for arch '$arch'"
63 | exit 1
64 | fi
65 |
66 | # Download Packages
67 | if [ "$package_manager" = apt ]; then
68 | curl -o "$TMP_DIR/NICE-GPG-KEY" "$CLOUDFRONT_PREFIX/NICE-GPG-KEY"
69 | gpg --import "$TMP_DIR/NICE-GPG-KEY"
70 | curl -o "$TMP_DIR/nice-dcv-session-manager-broker.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-session-manager-broker_all.$package_type.$package_extension"
71 | else
72 | rpm --import "$CLOUDFRONT_PREFIX"/NICE-GPG-KEY
73 | curl -o "$TMP_DIR/nice-dcv-session-manager-broker.$package_extension" "$CLOUDFRONT_PREFIX/nice-dcv-session-manager-broker-$package_type.noarch.$package_extension"
74 | fi
75 |
76 | # Install Packages
77 | for package_pattern in "nice-dcv-session-manager-broker.$package_extension"; do
78 | package_full_path=$(find "$TMP_DIR" -name "$package_pattern")
79 | "$package_manager" install -y "$package_full_path"
80 | done
81 |
82 | # Enable and start DCV Session Manager service
83 | systemctl start dcv-session-manager-broker
84 | systemctl enable dcv-session-manager-broker
85 |
86 | # Configure DCV Session Manager
87 | CONFIG_PATH="/etc/dcv-session-manager-broker/session-manager-broker.properties"
88 | ## Enable the gateway in config
89 | sed -i '/^enable-gateway/s/=.*$/= true/' "$CONFIG_PATH"
90 | ## Uncomment the broker connector host and port in config
91 | sed -i '/gateway-to-broker-connector-https-port/s/^#\s//g' "$CONFIG_PATH"
92 | sed -i '/gateway-to-broker-connector-bind-host/s/^#\s//g' "$CONFIG_PATH"
93 | ## (Optional) Enable the broker to persist on DynamoDB in config
94 | #sed -i '/^enable-persistence/s/=.*$/= true/' "$CONFIG_PATH"
95 | ### Uncomment database, region, Read Capacity Units(RCU), Write Capacity Units(WCU), and table name prefix in config
96 | #sed -i '/persistence-db/s/^#\s//g' "$CONFIG_PATH"
97 | #sed -i '/dynamodb-region/s/^#\s//g' "$CONFIG_PATH"
98 | #sed -i '/dynamodb-table-rcu/s/^#\s//g' "$CONFIG_PATH"
99 | #sed -i '/dynamodb-table-wcu/s/^#\s//g' "$CONFIG_PATH"
100 | #sed -i '/dynamodb-table-name-prefix/s/^#\s//g' "$CONFIG_PATH"
101 | #sed -i "/^dynamodb-region/s/=.*$/= $REGION/" "$CONFIG_PATH"
102 |
103 | # Restart the broker service
104 | systemctl restart dcv-session-manager-broker.service
105 |
106 | # Clean Up
107 | rm -rf "$TMP_DIR"
108 |
109 | # Get the private IP for connection gateway to use during configuration
110 | echo $(date -u) "Retrieving private broker DNS..." | tee -a "$LOG_PATH"
111 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
112 | MAC=`curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/network/interfaces/macs/`
113 | PRIVATE_DNS=`curl -H "X-aws-ec2-metadata-token: $TOKEN" "http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}local-hostname"`
114 | echo $(date -u) "Using private DNS $PRIVATE_DNS" | tee -a "$LOG_PATH"
115 |
116 | # Get current region
117 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
118 | echo $(date -u) "Current Region: $REGION" | tee -a "$LOG_PATH"
119 |
120 | # Store the private private DNS name in SSM Parameter Store
121 | echo $(date -u) "Storing broker private DNS name in AWS SSM Parameter Store..." | tee -a "$LOG_PATH"
122 | aws ssm put-parameter --name dcv-broker-private-dns --value "$PRIVATE_DNS" --type String --overwrite --region "$REGION"
123 | # Log if successful installation
124 | if [[ $? -eq 0 ]]; then
125 | echo $(date -u) "Stored private DNS name $PRIVATE_DNS in Parameter Store" | tee -a "$LOG_PATH"
126 | else
127 | echo $(date -u) "There was an error during DCV Session Manager installation" | tee -a "$LOG_PATH"
128 | fi
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/stacks/dcv_infra/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/dcv-samples/62554cb1deb94b843a7faceb94ff774b94f73243/cdk/dcv-gw-sm-without-pipelines/stacks/dcv_infra/__init__.py
--------------------------------------------------------------------------------
/cdk/dcv-gw-sm-without-pipelines/stacks/dcv_infra/dcv_infra.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | # this software and associated documentation files (the "Software"), to deal in
5 | # the Software without restriction, including without limitation the rights to
6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | # the Software, and to permit persons to whom the Software is furnished to do so.
8 | #
9 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import os
17 | from aws_cdk import Stack
18 | import aws_cdk as cdk
19 | import aws_cdk.aws_ec2 as ec2
20 | import aws_cdk.aws_iam as iam
21 | import aws_cdk.aws_kms as kms
22 | import aws_cdk.aws_autoscaling as autoscaling
23 | import aws_cdk.aws_elasticloadbalancingv2 as elbv2
24 | from constructs import Construct
25 |
26 | # The NICE DCV INFRA stack
27 | class DcvInfra(Stack):
28 | """ Class to deploy DCV infrastructure components """
29 | def __init__(self, scope: Construct, construct_id: str, config_data: dict, **kwargs) -> None:
30 | super().__init__(scope, construct_id, **kwargs)
31 |
32 | # Check if a VPC and subnets were provided in the config.json file
33 | if config_data['network']['vpcId'] and config_data['network']['publicASubnetId'] \
34 | and config_data['network']['publicBSubnetId'] \
35 | and config_data['network']['privateASubnetId'] \
36 | and config_data['network']['privateBSubnetId']:
37 | # Create reference for VPC
38 | vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=config_data['network']['vpcId'])
39 | # Create references for private and public subnets
40 | # using subnet_ids pulled from config.json
41 | subnets_public_ref_a = ec2.Subnet.from_subnet_attributes(
42 | self, "PublicSubnetAFromAttributes",
43 | subnet_id=config_data['network']['publicASubnetId'],
44 | availability_zone=f"{self.region}a"
45 | )
46 | subnets_public_ref_b = ec2.Subnet.from_subnet_attributes(
47 | self, "PublicSubnetBFromAttributes",
48 | subnet_id=config_data['network']['publicBSubnetId'],
49 | availability_zone=f"{self.region}b"
50 | )
51 | subnets_private_ref_a = ec2.Subnet.from_subnet_attributes(
52 | self, "PrivateSubnetAFromAttributes",
53 | subnet_id=config_data['network']['privateASubnetId'],
54 | availability_zone=f"{self.region}a"
55 | )
56 | subnets_private_ref_b = ec2.Subnet.from_subnet_attributes(
57 | self, "PrivateSubnetBFromAttributes",
58 | subnet_id=config_data['network']['privateBSubnetId'],
59 | availability_zone=f"{self.region}b"
60 | )
61 | subnets_public = ec2.SubnetSelection(
62 | subnets=[subnets_public_ref_a, subnets_public_ref_b]
63 | )
64 | subnets_private = ec2.SubnetSelection(
65 | subnets=[subnets_private_ref_a, subnets_private_ref_b]
66 | )
67 | else:
68 | # Create new VPC, subnets, and NAT Gateway
69 | vpc = ec2.Vpc(self, "VPC",
70 | nat_gateways = 1,
71 | max_azs = 2,
72 | subnet_configuration=[
73 | ec2.SubnetConfiguration(
74 | name = "public-subnet",
75 | subnet_type = ec2.SubnetType.PUBLIC,
76 | cidr_mask = 24,
77 | ),
78 | ec2.SubnetConfiguration(
79 | name = "private-subnet",
80 | subnet_type = ec2.SubnetType.PRIVATE_WITH_EGRESS,
81 | cidr_mask = 24
82 | )
83 | ],
84 | )
85 | # Create references for private and public subnets
86 | # using availability zones described above
87 | subnets_public = ec2.SubnetSelection(
88 | subnet_type=ec2.SubnetType.PUBLIC
89 | )
90 | subnets_private = ec2.SubnetSelection(
91 | subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS
92 | )
93 |
94 |
95 | # IAM Fleet Role Configuration
96 | role_fleet = iam.Role(self, "DCVFleetRole",
97 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
98 | role_name="dcv-fleet-role"
99 | )
100 |
101 | # IAM Session Manager Role Configuration
102 | role_session_mgr = iam.Role(self, "DCVSessionMgrRole",
103 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
104 | role_name="dcv-session-mgr-role"
105 | )
106 |
107 | # IAM Connection Gateway Role Configuration
108 | role_connection_gwy = iam.Role(self, "DCVConnectionGwyRole",
109 | assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
110 | role_name="dcv-connection-gwy-role"
111 | )
112 |
113 | # Permission to get NICE DCV License for fleet role
114 | role_fleet.add_to_policy(iam.PolicyStatement(
115 | effect=iam.Effect.ALLOW,
116 | actions=["s3:GetObject"],
117 | resources=[f"arn:aws:s3:::dcv-license.{self.region}/*"]
118 | ))
119 |
120 | role_fleet.add_managed_policy(
121 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore")
122 | )
123 |
124 | iam.CfnInstanceProfile(self, "DCVServerInstanceProfile",
125 | instance_profile_name="dcv-server-profile",
126 | roles=[role_fleet.role_name]
127 | )
128 |
129 | # Permission for SSM Parameter for Session Manager instance
130 | role_session_mgr.add_to_policy(iam.PolicyStatement(
131 | effect=iam.Effect.ALLOW,
132 | actions=[
133 | 'ssm:DescribeParameters'
134 | ],
135 | resources=[
136 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/*",
137 | ]
138 | ))
139 |
140 | role_session_mgr.add_to_policy(iam.PolicyStatement(
141 | effect=iam.Effect.ALLOW,
142 | actions=[
143 | 'ssm:PutParameter',
144 | 'ssm:GetParameter'
145 | ],
146 | resources=[
147 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/dcv-broker-private-dns",
148 | ]
149 | ))
150 |
151 | role_session_mgr.add_managed_policy(
152 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore")
153 | )
154 |
155 | # Permission for SSM Parameter for Session Manager instance
156 | role_connection_gwy.add_to_policy(iam.PolicyStatement(
157 | effect=iam.Effect.ALLOW,
158 | actions=[
159 | 'ssm:DescribeParameters'
160 | ],
161 | resources=[
162 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/*",
163 | ]
164 | ))
165 |
166 | # Permission to read the SSM Parameter for Connection Gateway instance
167 | role_connection_gwy.add_to_policy(iam.PolicyStatement(
168 | effect=iam.Effect.ALLOW,
169 | actions=[
170 | 'ssm:GetParameter'
171 | ],
172 | resources=[
173 | f"arn:aws:ssm:{self.region}:{self.account}:parameter/dcv-broker-private-dns"
174 | ]
175 | ))
176 |
177 | # Add managed policy to allow CloudWatch logs and SSM
178 | role_connection_gwy.add_managed_policy(
179 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore"))
180 |
181 | # Session Manager Security Group configuration
182 | sg_session_mgr = ec2.SecurityGroup(self, "SMSecurityGroup",
183 | vpc=vpc,
184 | description="Default ports for DCV Session, Gateway, and Broker",
185 | allow_all_outbound=True, #Egress all
186 | disable_inline_rules=True
187 | )
188 |
189 | # Add Ingress for Nice DCV TCP/UDP Ports
190 | sg_session_mgr.add_ingress_rule(
191 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8443), "allow CLI to Broker communication"
192 | )
193 | sg_session_mgr.add_ingress_rule(
194 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8445), "allow Agent to Broker communication"
195 | )
196 | sg_session_mgr.add_ingress_rule(
197 | sg_session_mgr, ec2.Port.all_traffic(), "allow Broker to Broker communication"
198 | )
199 |
200 | # Connection Gateway Security Group configuration
201 | sg_connection_gwy = ec2.SecurityGroup(self, "CGSecurityGroup",
202 | vpc=vpc,
203 | description="SG default ports for DCV Connection Gateway",
204 | allow_all_outbound=True, #Egress all
205 | disable_inline_rules=True
206 | )
207 |
208 | sg_connection_gwy.add_ingress_rule(
209 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8443), "allow TCP DCV access from public internet"
210 | )
211 | sg_connection_gwy.add_ingress_rule(
212 | ec2.Peer.any_ipv4(), ec2.Port.udp(8443), "allow UDP DCV access from public internet"
213 | )
214 | sg_connection_gwy.add_ingress_rule(
215 | ec2.Peer.any_ipv4(), ec2.Port.tcp(8989), "allow health check for NLB targets"
216 | )
217 |
218 | # Gateway to Session Manager resolver communication
219 | sg_session_mgr.add_ingress_rule(
220 | sg_connection_gwy, ec2.Port.tcp(8447), "allow Gateway to Broker resolver communication"
221 | )
222 |
223 | # DCV server fleet Security Group configuration
224 | sg_dcv_server = ec2.SecurityGroup(self, "DCVServerSecurityGroup",
225 | vpc=vpc,
226 | description="SG default ports for DCV Connection Gateway",
227 | allow_all_outbound=True, #Egress all
228 | disable_inline_rules=True
229 | )
230 |
231 | sg_dcv_server.add_ingress_rule(
232 | sg_connection_gwy, ec2.Port.tcp(8443), "allow DCV streaming traffic from Gateway"
233 | )
234 | sg_dcv_server.add_ingress_rule(
235 | sg_connection_gwy, ec2.Port.udp(8443), "allow DCV streaming traffic from Gateway"
236 | )
237 |
238 | # Get KMS Key from Alias/Key Name
239 | kms_arn = f"arn:aws:kms:{self.region}:{self.account}:alias/{config_data['kmsKeyName']}"
240 | kms_key = kms.Key.from_key_arn(self, "kms-key", kms_arn)
241 |
242 | # Session Manager
243 | ### Session Manager AMI
244 | session_mgr_ami = ec2.GenericLinuxImage({
245 | self.region : config_data['sessionMgr']['baseAmiId']
246 | }
247 | )
248 |
249 | # Add the user data script to custom string
250 | session_mgr_user_data_file = open(os.path.join(os.path.dirname( __file__ ),
251 | "..", "..",
252 | "scripts",
253 | "session-mgr-user-data.sh"),
254 | "r", encoding="utf-8")
255 | session_mgr_user_data_content = session_mgr_user_data_file.read()
256 | session_mgr_user_data = ec2.UserData.custom(session_mgr_user_data_content)
257 |
258 | # Create a reference to the SSH Key Pair name given in the config.json file
259 | key_pair = ec2.KeyPair.from_key_pair_attributes(self, "DCVKeyPair",
260 | key_pair_name=config_data['sshKeypairName']
261 | )
262 |
263 | # Create the Session Manager EC2 instance
264 | session_mgr_instance = ec2.Instance(self, "SessionMgrInstance",
265 | vpc=vpc,
266 | vpc_subnets=subnets_private,
267 | instance_type=ec2.InstanceType.of(
268 | ec2.InstanceClass.M6G, ec2.InstanceSize.LARGE),
269 | machine_image=session_mgr_ami,
270 | security_group=sg_session_mgr,
271 | key_pair=key_pair,
272 | user_data=session_mgr_user_data,
273 | role=role_session_mgr,
274 | block_devices=[ec2.BlockDevice(
275 | device_name="/dev/xvda",
276 | volume=ec2.BlockDeviceVolume.ebs(
277 | 8, encrypted=True, kms_key=kms_key))]
278 | )
279 |
280 | # Connection Gateway
281 | ### Connection Gateway AMI
282 | connection_gwy_ami = ec2.GenericLinuxImage({
283 | self.region : config_data['connectionGwy']['baseAmiId']
284 | })
285 |
286 | # Add the user data script to custom string
287 | connection_gwy_user_data_file = open(os.path.join(os.path.dirname( __file__ ),
288 | "..", "..",
289 | "scripts",
290 | "connection-gwy-user-data.sh"),
291 | "r", encoding="utf-8")
292 |
293 | connection_gwy_user_data_content = connection_gwy_user_data_file.read()
294 | connection_gwy_session_mgr_user_data = ec2.UserData.custom(connection_gwy_user_data_content)
295 |
296 | # Create an EC2 launch template with the encrypted volume for Connection Gateway
297 | connection_gwy_launch_template = ec2.LaunchTemplate(self, "ConnectionGwyLaunchTemplate",
298 | machine_image=connection_gwy_ami,
299 | security_group=sg_connection_gwy,
300 | instance_type=ec2.InstanceType.of(
301 | ec2.InstanceClass.C7G, ec2.InstanceSize.LARGE),
302 | key_pair=key_pair,
303 | user_data=connection_gwy_session_mgr_user_data,
304 | role=role_connection_gwy,
305 | block_devices=[ec2.BlockDevice(
306 | device_name="/dev/xvda",
307 | volume=ec2.BlockDeviceVolume.ebs(
308 | 8, encrypted=True, kms_key=kms_key))],
309 | )
310 |
311 | # Create a Connection Gateway Auto Scaling Group
312 | connection_gwy_asg = autoscaling.AutoScalingGroup(self, "ConnectionGwyASG",
313 | vpc=vpc,
314 | launch_template=connection_gwy_launch_template,
315 | min_capacity=1,
316 | max_capacity=5,
317 | desired_capacity=1,
318 | vpc_subnets=subnets_private
319 | )
320 |
321 | # Ensure Session Manager instance is created before Connection Gateway targets
322 | connection_gwy_asg.node.add_dependency(session_mgr_instance)
323 |
324 | # Connection Gateway Auto Scaling Group CPU Utilization to scale
325 | connection_gwy_asg.scale_on_cpu_utilization(
326 | "ConnectionGwyASGCPUUtilization", target_utilization_percent=75
327 | )
328 |
329 | # Create a Connection Gateway Network Load Balancer
330 | connection_gwy_nlb = elbv2.NetworkLoadBalancer(self, "ConnectionGwyNLB",
331 | vpc=vpc,
332 | internet_facing=True,
333 | vpc_subnets=subnets_public,
334 | load_balancer_name="connection-gwy-nlb",
335 | cross_zone_enabled=True
336 | )
337 |
338 | # Connection Gateway Listener to Target Setup for NLB
339 | connection_gwy_listener = connection_gwy_nlb.add_listener(
340 | "ConnectionGwyNLBListener", port=8443, protocol=elbv2.Protocol.TCP_UDP
341 | )
342 |
343 | # Route the Connection Gateway targets
344 | connection_gwy_listener.add_targets("ConnectionGwyNLBTarget",
345 | port=8443,
346 | protocol=elbv2.Protocol.TCP_UDP,
347 | health_check=elbv2.HealthCheck(
348 | port="8989",
349 | protocol=elbv2.Protocol.TCP,
350 | unhealthy_threshold_count=5,
351 | healthy_threshold_count=5,
352 | interval=cdk.Duration.seconds(30)
353 | ),
354 | targets=[connection_gwy_asg]
355 | )
356 |
--------------------------------------------------------------------------------
/session-resolver/resolver.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: MIT-0
3 |
4 | import json
5 | import boto3
6 | from botocore.exceptions import ClientError
7 |
8 | ec2 = boto3.client('ec2')
9 |
10 | TCP_PORT = 8443
11 | UDP_PORT = 8443
12 |
13 | def get_instance_ip(instance_id):
14 | """ Given an instance ID this returns the private Ip address corresponding to it """
15 | try:
16 | response = ec2.describe_instances(InstanceIds=[instance_id])
17 | private_ip_addr = response['Reservations'][0]['Instances'][0]['PrivateIpAddress']
18 | return private_ip_addr
19 | except ClientError:
20 | return {
21 | 'statusCode': 404,
22 | 'body': f"Invalid session ID '{instance_id}'."
23 | }
24 |
25 |
26 | # https://docs.aws.amazon.com/dcv/latest/gw-admin/session-resolver.html#implementing-session-resolver
27 | def lambda_handler(event, context):
28 | # Gateway POST - sessionId=session_id&transport=transport&clientIpAddress=clientIpAddress
29 | session_id = event['queryStringParameters']['sessionId']
30 | transport = event['queryStringParameters']['transport']
31 |
32 | if session_id is None:
33 | return {
34 | 'statusCode': 400,
35 | 'body': "Missing sessionId parameter"
36 | }
37 |
38 | if transport not in ["HTTP", "QUIC"]:
39 | return {
40 | 'statusCode': 400,
41 | 'body': "Invalid transport parameter: " + transport
42 | }
43 |
44 | server_endpoint = get_instance_ip(session_id)
45 | port = int(TCP_PORT if transport == 'HTTP' else UDP_PORT)
46 | session_details = {
47 | 'SessionId': "console",
48 | 'DcvServerEndpoint': server_endpoint,
49 | 'Port': port,
50 | 'WebUrlPath': '/',
51 | 'TransportProtocol':transport
52 | }
53 | if 'statusCode' in server_endpoint:
54 | return server_endpoint
55 | if 'statusCode' not in server_endpoint:
56 | return {
57 | 'statusCode': 200,
58 | 'body': json.dumps(session_details)
59 | }
60 |
--------------------------------------------------------------------------------
/usage-reporting/Build-DCVUsageReports.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
5 | software and associated documentation files (the "Software"), to deal in the Software
6 | without restriction, including without limitation the rights to use, copy, modify,
7 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | .SYNOPSIS
18 | This script is intended to generate usage reports for DCV Amazon WorkSpaces.
19 | .DESCRIPTION
20 | A scheduled task should be pushed via Group Policy that will invoke the local script every minute
21 | on a WSP WorkSpace. The script will create a CSV for each day and records hostname, sessions start time,
22 | session end time, username, and total session duration. These reports can be further analyzed by ingesting
23 | into a visualization logging mechanism. To deploy this task, it is recommended to use a Group Policy Object,
24 | as WorkSpaces require AD DS. Alternatively, the scheduled task can be created locally.
25 | .EXAMPLE
26 | Scheduled task argument to execute local script. Path can be modified to your script location.
27 | -noprofile -ExecutionPolicy Unrestricted -file "C:\Program Files\Amazon\Build-DCVUsageReports.ps1"
28 | Scheduled task argument to execute local script with a provided path. The path must exist locally.
29 | -noprofile -ExecutionPolicy Unrestricted -file "C:\Program Files\Amazon\Build-DCVUsageReports.ps1" -usageReportsFolder "C:\path"
30 | #>
31 | [CmdletBinding()]
32 | Param (
33 | [Parameter(Mandatory=$false)]
34 | [string]$usageReportsFolder
35 | )
36 |
37 | $today = Get-Date
38 | $reportId = $today.Month.ToString() + "-" + $today.Day.ToString() + "-" + $today.Year.ToString()
39 | if($usageReportsFolder -eq ''){
40 | $usageReportsFolder = "C:\Windows\Temp\DCVUsageReports"
41 | }else{
42 | if(-not(Test-Path -Path $usageReportsFolder)){
43 | write-host "Provided path not found. Reverting to default path."
44 | $usageReportsFolder = "C:\Windows\Temp\DCVUsageReports"
45 | }
46 | }
47 | $outfile = "$usageReportsFolder\$reportId.csv"
48 | if(-not(Test-Path -Path $usageReportsFolder)){
49 | New-Item $usageReportsFolder -ItemType Directory -ea 0
50 | }
51 | if(-not(Test-Path -Path $outfile)){
52 | {} | Select "Hostname","LogonTime","LogoffTime","User","SessionTime" | Export-Csv $outfile -NoTypeInformation
53 | }
54 | $hostname = $env:computername
55 | $sessionInfo = .'C:\Program Files\NICE\DCV\Server\bin\dcv.exe' list-sessions console -j | ConvertFrom-Json
56 | if ($sessionInfo.'num-of-connections' -ne 0){
57 | $connectionInfo = .'C:\Program Files\NICE\DCV\Server\bin\dcv.exe' list-connections console -j | ConvertFrom-Json
58 | if ($connectionInfo.count -eq 1){
59 | $user = $connectionInfo.username
60 | }else{
61 | $user = $connectionInfo[0].username
62 | }
63 | $sessionStart = '{0:HH:mm:ss}' -f ([DateTime](($connectionInfo.'connection-time').Split('T')).Split('.')[1])
64 | $importReport = Import-CSV -Path $outfile
65 | if (-not($importReport.LogonTime.Contains($sessionStart))){
66 | $inputLogonTime = [PSCustomObject]@{
67 | Hostname = $hostname
68 | LogonTime = $sessionStart
69 | LogoffTime = ''
70 | User = $user
71 | SessionTime = '00:00:00'
72 | }
73 | $inputLogonTime | Export-Csv $outfile -Append
74 | }
75 | }
76 | if ($sessionInfo.'last-disconnection-time' -ne ''){
77 | if (([DateTime]($sessionInfo.'last-disconnection-time').Split('T')[0]).Day -eq $today.Day){
78 | $disconnectedTime = '{0:HH:mm:ss}' -f ([DateTime]((($sessionInfo.'last-disconnection-time')).Split('T')).Split('.')[1])
79 | }else{
80 | $disconnectedTime = ''
81 | }
82 | }else{
83 | $disconnectedTime = ''
84 | }
85 | $importReport = Import-CSV -Path $outfile
86 | $updateReport = foreach ($line in $importReport){
87 | if (($line.LogoffTime -eq '') -and ($line.LogonTime -ne '') -and ($disconnectedTime -ne '')){
88 | if ((New-TimeSpan -Start $disconnectedTime -End $today) -lt (New-TimeSpan -Start $line.LogonTime -End $today)){
89 | $line.LogoffTime = $disconnectedTime
90 | $sessionTime = New-TimeSpan -Start $line.LogonTime -End $line.LogoffTime
91 | $sessionTime = $sessionTime.Hours.ToString() + ':' + $sessionTime.Minutes.ToString() + ':' +$sessionTime.Seconds.ToString()
92 | $line.SessionTime = $sessionTime
93 | }
94 | $line
95 | } elseif ($line.LogonTime -ne ''){
96 | $line
97 | }
98 | }
99 | $updateReport | Export-Csv $outfile -NoTypeInformation
100 | $verifyFile = Get-Content $outfile
101 | if ($null -eq $verifyFile){
102 | {} | Select "Hostname","LogonTime","LogoffTime","User","SessionTime" | Export-Csv $outfile -NoTypeInformation
103 | }
--------------------------------------------------------------------------------
/usage-reporting/Build-WSPUsageReports.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
5 | software and associated documentation files (the "Software"), to deal in the Software
6 | without restriction, including without limitation the rights to use, copy, modify,
7 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 |
17 | .SYNOPSIS
18 | This script is intended to generate usage reports for WSP Amazon WorkSpaces.
19 | .DESCRIPTION
20 | A scheduled task should be pushed via Group Policy that will invoke the local script every minute
21 | on a WSP WorkSpace. The script will create a CSV for each day and records hostname, sessions start time,
22 | session end time, username, and total session duration. These reports can be further analyzed by ingesting
23 | into a visualization logging mechanism. To deploy this task, it is recommended to use a Group Policy Object,
24 | as WorkSpaces require AD DS. Alternatively, the scheduled task can be created locally.
25 | .EXAMPLE
26 | Scheduled task argument to execute local script. Path can be modified to your script location.
27 | -noprofile -ExecutionPolicy Unrestricted -file "C:\Program Files\Amazon\Build-WSPUsageReports.ps1"
28 | Scheduled task argument to execute local script with a provided path. The path must exist locally.
29 | -noprofile -ExecutionPolicy Unrestricted -file "C:\Program Files\Amazon\Build-WSPUsageReports.ps1" -usageReportsFolder "C:\path"
30 | #>
31 | [CmdletBinding()]
32 | Param (
33 | [Parameter(Mandatory=$false)]
34 | [string]$usageReportsFolder
35 | )
36 |
37 | $today = Get-Date
38 | $reportId = $today.Month.ToString() + "-" + $today.Day.ToString() + "-" + $today.Year.ToString()
39 | if($usageReportsFolder -eq ''){
40 | $usageReportsFolder = "C:\Windows\Temp\WSPUsageReports"
41 | }else{
42 | if(-not(Test-Path -Path $usageReportsFolder)){
43 | write-host "Provided path not found. Reverting to default path."
44 | $usageReportsFolder = "C:\Windows\Temp\WSPUsageReports"
45 | }
46 | }
47 | $outfile = "$usageReportsFolder\$reportId.csv"
48 | if(-not(Test-Path -Path $usageReportsFolder)){
49 | New-Item $usageReportsFolder -ItemType Directory -ea 0
50 | }
51 | if(-not(Test-Path -Path $outfile)){
52 | {} | Select "Hostname","LogonTime","LogoffTime","User","SessionTime" | Export-Csv $outfile -NoTypeInformation
53 | }
54 | $hostname = $env:computername
55 | $user = (Get-ChildItem D:\Users\)[0].Name
56 | $sessionInfo = .'C:\Program Files\NICE\DCV\Server\bin\dcv.exe' list-sessions console -j | ConvertFrom-Json
57 | if ($sessionInfo.'num-of-connections' -ne 0){
58 | $connectionInfo = .'C:\Program Files\NICE\DCV\Server\bin\dcv.exe' list-connections console -j | ConvertFrom-Json
59 | $sessionStart = '{0:HH:mm:ss}' -f ([DateTime](($connectionInfo.'connection-time').Split('T')).Split('.')[1])
60 | $importReport = Import-CSV -Path $outfile
61 | if (-not($importReport.LogonTime.Contains($sessionStart))){
62 | $inputLogonTime = [PSCustomObject]@{
63 | Hostname = $hostname
64 | LogonTime = $sessionStart
65 | LogoffTime = ''
66 | User = $user
67 | SessionTime = '00:00:00'
68 | }
69 | $inputLogonTime | Export-Csv $outfile -Append
70 | }
71 | }
72 | if ($sessionInfo.'last-disconnection-time' -ne ''){
73 | if (([DateTime]($sessionInfo.'last-disconnection-time').Split('T')[0]).Day -eq $today.Day){
74 | $disconnectedTime = '{0:HH:mm:ss}' -f ([DateTime]((($sessionInfo.'last-disconnection-time')).Split('T')).Split('.')[1])
75 | }else{
76 | $disconnectedTime = ''
77 | }
78 | }else{
79 | $disconnectedTime = ''
80 | }
81 | $importReport = Import-CSV -Path $outfile
82 | $updateReport = foreach ($line in $importReport){
83 | if (($line.LogoffTime -eq '') -and ($line.LogonTime -ne '') -and ($disconnectedTime -ne '')){
84 | if ((New-TimeSpan -Start $disconnectedTime -End $today) -lt (New-TimeSpan -Start $line.LogonTime -End $today)){
85 | $line.LogoffTime = $disconnectedTime
86 | $sessionTime = New-TimeSpan -Start $line.LogonTime -End $line.LogoffTime
87 | $sessionTime = $sessionTime.Hours.ToString() + ':' + $sessionTime.Minutes.ToString() + ':' +$sessionTime.Seconds.ToString()
88 | $line.SessionTime = $sessionTime
89 | }
90 | $line
91 | } elseif ($line.LogonTime -ne ''){
92 | $line
93 | }
94 | }
95 | $updateReport | Export-Csv $outfile -NoTypeInformation
96 | $verifyFile = Get-Content $outfile
97 | if ($null -eq $verifyFile){
98 | {} | Select "Hostname","LogonTime","LogoffTime","User","SessionTime" | Export-Csv $outfile -NoTypeInformation
99 | }
--------------------------------------------------------------------------------