-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new infrastructure and script files for user management and VM ac…
…cess - Create GitHub Actions workflow for validating PowerShell scripts using PSScriptAnalyzer. - Add Heat templates for deploying Windows and Linux instances with networking configurations. - Implement PowerShell script to generate a CSV of Active Directory users with random credentials. - Create Bash scripts for accessing VMs via RDP on Linux and macOS. - Introduce a new YAML template for deploying a single Ubuntu instance. - Update existing YAML templates for Windows Server and Windows 10 instances with floating IPs.
- Loading branch information
Showing
11 changed files
with
1,046 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # .github/workflows/validate.yml | ||
| name: Validate PowerShell Scripts | ||
|
|
||
| on: | ||
| push: | ||
| paths: | ||
| - "scripts/**/*.ps1" | ||
| - ".github/workflows/validate.yml" | ||
| pull_request: | ||
| paths: | ||
| - "scripts/**/*.ps1" | ||
| - ".github/workflows/validate.yml" | ||
|
|
||
| jobs: | ||
| validate: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Install PSScriptAnalyzer | ||
| shell: pwsh | ||
| run: | | ||
| Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted | ||
| Install-Module PSScriptAnalyzer -Scope CurrentUser -Force -SkipPublisherCheck | ||
| - name: Run ScriptAnalyzer | ||
| shell: pwsh | ||
| run: | | ||
| Invoke-ScriptAnalyzer -EnableExit scripts/*.ps1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| heat_template_version: 2013-05-23 | ||
|
|
||
| description: > | ||
| HOT template to create a new neutron network plus a router to the public | ||
| network, and for deploying one Windows 10 (hostname cl1) and two Windows | ||
| Servers (hostnames dc1 and srv1) without any configuration (only cl1 has | ||
| a boot script to set correct hostname). | ||
| parameters: | ||
| key_name: | ||
| type: string | ||
| description: Name of keypair to assign to servers | ||
|
|
||
| resources: | ||
| private_net: | ||
| type: OS::Neutron::Net | ||
|
|
||
| private_subnet: | ||
| type: OS::Neutron::Subnet | ||
| properties: | ||
| network_id: { get_resource: private_net } | ||
| cidr: 192.168.111.0/24 | ||
| gateway_ip: 192.168.111.1 | ||
| allocation_pools: | ||
| - start: 192.168.111.101 | ||
| end: 192.168.111.200 | ||
|
|
||
| router: | ||
| type: OS::Neutron::Router | ||
| properties: | ||
| external_gateway_info: | ||
| network: ntnu-internal | ||
|
|
||
| router_interface: | ||
| type: OS::Neutron::RouterInterface | ||
| properties: | ||
| router_id: { get_resource: router } | ||
| subnet_id: { get_resource: private_subnet } | ||
|
|
||
| sec_core: | ||
| type: OS::Neutron::SecurityGroup | ||
| properties: | ||
| description: Security group rules for all | ||
| name: sec_core | ||
| rules: | ||
| - remote_ip_prefix: 0.0.0.0/0 | ||
| protocol: icmp | ||
| - remote_ip_prefix: 0.0.0.0/0 | ||
| protocol: tcp | ||
| port_range_min: 22 | ||
| port_range_max: 22 | ||
| - remote_ip_prefix: 0.0.0.0/0 | ||
| protocol: tcp | ||
| port_range_min: 80 | ||
| port_range_max: 80 | ||
| - remote_ip_prefix: 0.0.0.0/0 | ||
| protocol: tcp | ||
| port_range_min: 443 | ||
| port_range_max: 443 | ||
| - remote_ip_prefix: 0.0.0.0/0 | ||
| protocol: tcp | ||
| port_range_min: 3389 | ||
| port_range_max: 3389 | ||
|
|
||
| mgr: | ||
| type: OS::Nova::Server | ||
| properties: | ||
| name: mgr | ||
| image: 'Windows 11 22H2 Enterprise [Evaluation]' | ||
| flavor: gx1.2c4r | ||
| key_name: { get_param: key_name } | ||
| networks: | ||
| - port: { get_resource: mgr_port } | ||
| user_data_format: RAW | ||
| user_data: | | ||
| #ps1_sysnative | ||
| # | ||
| # Windows 10 doesn't set hostname correctly | ||
| # | ||
| $name = (New-Object System.Net.WebClient).DownloadString("http://169.254.169.254/latest/meta-data/hostname") | ||
| $shortname = $name.split('.',2)[0] | ||
| if ( $env:computername -ne $shortname ) { | ||
| Rename-Computer $shortname | ||
| exit 1003 # 1003 - reboot and run the plugin again on next boot | ||
| # https://cloudbase-init.readthedocs.io/en/latest/tutorial.html#file-execution | ||
| } | ||
| mgr_port: | ||
| type: OS::Neutron::Port | ||
| properties: | ||
| network_id: { get_resource: private_net } | ||
| security_groups: | ||
| - default | ||
| - { get_resource: sec_core } | ||
| fixed_ips: | ||
| - subnet_id: { get_resource: private_subnet } | ||
| mgr_floating_ip: | ||
| type: OS::Neutron::FloatingIP | ||
| properties: | ||
| floating_network: ntnu-internal | ||
| port_id: { get_resource: mgr_port } | ||
|
|
||
| cl1: | ||
| type: OS::Nova::Server | ||
| properties: | ||
| name: cl1 | ||
| image: 'Windows 11 22H2 Enterprise [Evaluation]' | ||
| flavor: gx1.2c4r | ||
| key_name: { get_param: key_name } | ||
| networks: | ||
| - port: { get_resource: cl1_port } | ||
| user_data_format: RAW | ||
| user_data: | | ||
| #ps1_sysnative | ||
| # | ||
| # Windows 10 doesn't set hostname correctly | ||
| # | ||
| $name = (New-Object System.Net.WebClient).DownloadString("http://169.254.169.254/latest/meta-data/hostname") | ||
| $shortname = $name.split('.',2)[0] | ||
| if ( $env:computername -ne $shortname ) { | ||
| Rename-Computer $shortname | ||
| exit 1003 # 1003 - reboot and run the plugin again on next boot | ||
| # https://cloudbase-init.readthedocs.io/en/latest/tutorial.html#file-execution | ||
| } | ||
| cl1_port: | ||
| type: OS::Neutron::Port | ||
| properties: | ||
| network_id: { get_resource: private_net } | ||
| security_groups: | ||
| - default | ||
| - { get_resource: sec_core } | ||
| fixed_ips: | ||
| - subnet_id: { get_resource: private_subnet } | ||
| cl1_floating_ip: | ||
| type: OS::Neutron::FloatingIP | ||
| properties: | ||
| floating_network: ntnu-internal | ||
| port_id: { get_resource: cl1_port } | ||
|
|
||
| dc1: | ||
| type: OS::Nova::Server | ||
| properties: | ||
| name: dc1 | ||
| image: 'Windows Server 2025 Standard [Evaluation]' | ||
| flavor: gx1.2c4r | ||
| key_name: { get_param: key_name } | ||
| networks: | ||
| - port: { get_resource: dc1_port } | ||
| dc1_port: | ||
| type: OS::Neutron::Port | ||
| properties: | ||
| network_id: { get_resource: private_net } | ||
| security_groups: | ||
| - default | ||
| - { get_resource: sec_core } | ||
| fixed_ips: | ||
| - subnet_id: { get_resource: private_subnet } | ||
| dc1_floating_ip: | ||
| type: OS::Neutron::FloatingIP | ||
| properties: | ||
| floating_network: ntnu-internal | ||
| port_id: { get_resource: dc1_port } | ||
|
|
||
| srv1: | ||
| type: OS::Nova::Server | ||
| properties: | ||
| name: srv1 | ||
| image: 'Windows Server 2025 Standard [Evaluation]' | ||
| flavor: gx1.2c4r | ||
| key_name: { get_param: key_name } | ||
| networks: | ||
| - port: { get_resource: srv1_port } | ||
| srv1_port: | ||
| type: OS::Neutron::Port | ||
| properties: | ||
| network_id: { get_resource: private_net } | ||
| security_groups: | ||
| - default | ||
| - { get_resource: sec_core } | ||
| fixed_ips: | ||
| - subnet_id: { get_resource: private_subnet } | ||
| srv1_floating_ip: | ||
| type: OS::Neutron::FloatingIP | ||
| properties: | ||
| floating_network: ntnu-internal | ||
| port_id: { get_resource: srv1_port } | ||
|
|
||
| outputs: | ||
| srv1_private_ip: | ||
| description: IP address of srv1 in private network | ||
| value: { get_attr: [ srv1, first_address ] } | ||
| srv1_public_ip: | ||
| description: Floating IP address of srv1 in public network | ||
| value: { get_attr: [ srv1_floating_ip, floating_ip_address ] } | ||
| dc1_private_ip: | ||
| description: IP address of dc1 in private network | ||
| value: { get_attr: [ dc1, first_address ] } | ||
| dc1_public_ip: | ||
| description: Floating IP address of dc1 in public network | ||
| value: { get_attr: [ dc1_floating_ip, floating_ip_address ] } | ||
| cl1_private_ip: | ||
| description: IP address of cl1 in private network | ||
| value: { get_attr: [ cl1, first_address ] } | ||
| cl1_public_ip: | ||
| description: Floating IP address of cl1 in public network | ||
| value: { get_attr: [ cl1_floating_ip, floating_ip_address ] } | ||
| mgr_private_ip: | ||
| description: IP address of mgr in private network | ||
| value: { get_attr: [ mgr, first_address ] } | ||
| mgr_public_ip: | ||
| description: Floating IP address of mgr in public network | ||
| value: { get_attr: [ mgr_floating_ip, floating_ip_address ] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| # Usage: | ||
| # .\CreateUserCSV.ps1 | ||
| # will create the csv-file which can be used like this (if sec.core domain prepared): | ||
| # $ADUsers = Import-Csv seccoreusers.csv -Delimiter ';' | ||
| # # Headers: Username;GivenName;SurName;UserPrincipalName;DisplayName;Password;Department;Path | ||
| # foreach ($User in $ADUsers) { | ||
| # if (!(Get-ADUser -LDAPFilter ` | ||
| # "(sAMAccountName=$($User.Username))")) { | ||
| # New-ADUser ` | ||
| # -SamAccountName $User.Username ` | ||
| # -UserPrincipalName $User.UserPrincipalName ` | ||
| # -Name $User.DisplayName ` | ||
| # -GivenName $User.GivenName ` | ||
| # -Surname $User.SurName ` | ||
| # -Enabled $True ` | ||
| # -ChangePasswordAtLogon $False ` | ||
| # -DisplayName $user.Displayname ` | ||
| # -Department $user.Department ` | ||
| # -Path $user.path ` | ||
| # -AccountPassword (ConvertTo-SecureString $user.Password -AsPlainText | ||
| # -Force) | ||
| # } | ||
| # } | ||
|
|
||
| # Run this script to create your own list of 100 users for the SEC.CORE | ||
| # infrastructure as a CSV-file | ||
| # Each time the script is run, it will create a new random combination | ||
| # of firstname (which is also the username), lastname and department | ||
| # New unique random passwords are generated for every user | ||
|
|
||
| # Test so we don't overwrite a file by accident | ||
| # | ||
| if ((Get-ChildItem -ErrorAction SilentlyContinue seccoreusers.csv).Exists) | ||
| {"You alread have the file seccoreusers.csv!"; return;} | ||
| if ($PSVersionTable.PSVersion.Major -eq 5) | ||
| {Write-Output "This script cannot be executed in Windows PowerShell, please use PowerShell core"; return;} | ||
|
|
||
| # 100 unique firstnames without norwegian characters ('øæå') | ||
| # | ||
| $FirstName = @("Nora","Emma","Ella","Maja","Olivia","Emilie","Sofie","Leah", | ||
| "Sofia","Ingrid","Frida","Sara","Tiril","Selma","Ada","Hedda", | ||
| "Amalie","Anna","Alma","Eva","Mia","Thea","Live","Ida","Astrid", | ||
| "Ellinor","Vilde","Linnea","Iben","Aurora","Mathilde","Jenny", | ||
| "Tuva","Julie","Oda","Sigrid","Amanda","Lilly","Hedvig", | ||
| "Victoria","Amelia","Josefine","Agnes","Solveig","Saga","Marie", | ||
| "Eline","Oline","Maria","Hege","Jakob","Emil","Noah","Oliver", | ||
| "Filip","William","Lucas","Liam","Henrik","Oskar","Aksel", | ||
| "Theodor","Elias","Kasper","Magnus","Johannes","Isak","Mathias", | ||
| "Tobias","Olav","Sander","Haakon","Jonas","Ludvig","Benjamin", | ||
| "Matheo","Alfred","Alexander","Victor","Markus","Theo", | ||
| "Mohammad","Herman","Adam","Ulrik","Iver","Sebastian","Johan", | ||
| "Odin","Leon","Nikolai","Even","Leo","Kristian","Mikkel", | ||
| "Gustav","Felix","Sverre","Adrian","Lars" | ||
| ) | ||
|
|
||
| # 100 unique lastnames | ||
| # | ||
| $LastName = @("Hansen","Johansen","Olsen","Larsen","Andersen","Pedersen", | ||
| "Nilsen","Kristiansen","Jensen","Karlsen","Johnsen","Pettersen", | ||
| "Eriksen","Berg","Haugen","Hagen","Johannessen","Andreassen", | ||
| "Jacobsen","Dahl","Jørgensen","Henriksen","Lund","Halvorsen", | ||
| "Sørensen","Jakobsen","Moen","Gundersen","Iversen","Strand", | ||
| "Solberg","Svendsen","Eide","Knutsen","Martinsen","Paulsen", | ||
| "Bakken","Kristoffersen","Mathisen","Lie","Amundsen","Nguyen", | ||
| "Rasmussen","Ali","Lunde","Solheim","Berge","Moe","Nygård", | ||
| "Bakke","Kristensen","Fredriksen","Holm","Lien","Hauge", | ||
| "Christensen","Andresen","Nielsen","Knudsen","Evensen","Sæther", | ||
| "Aas","Myhre","Hanssen","Ahmed","Haugland","Thomassen", | ||
| "Sivertsen","Simonsen","Danielsen","Berntsen","Sandvik", | ||
| "Rønning","Arnesen","Antonsen","Næss","Vik","Haug","Ellingsen", | ||
| "Thorsen","Edvardsen","Birkeland","Isaksen","Gulbrandsen","Ruud", | ||
| "Aasen","Strøm","Myklebust","Tangen","Ødegård","Eliassen", | ||
| "Helland","Bøe","Jenssen","Aune","Mikkelsen","Tveit","Brekke", | ||
| "Abrahamsen","Madsen" | ||
| ) | ||
|
|
||
| # 2 in IT, 8 in Adm and 30 consultants in each of in each of Blue, Red and DFIR | ||
| # | ||
| $OrgUnits = @("ou=IT,ou=AllUsers","ou=IT,ou=AllUsers", | ||
| "ou=Adm,ou=AllUsers","ou=Adm,ou=AllUsers","ou=Adm,ou=AllUsers", | ||
| "ou=Adm,ou=AllUsers","ou=Adm,ou=AllUsers","ou=Adm,ou=AllUsers", | ||
| "ou=Adm,ou=AllUsers","ou=Adm,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Blue,ou=Cons,ou=AllUsers","ou=Blue,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=Red,ou=Cons,ou=AllUsers","ou=Red,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers", | ||
| "ou=DFIR,ou=Cons,ou=AllUsers","ou=DFIR,ou=Cons,ou=AllUsers" | ||
| ) | ||
|
|
||
| # Three shuffled indices to randomly mix firstname, lastname, and department | ||
| # | ||
| $fnidx = 0..99 | Get-Random -Shuffle | ||
| $lnidx = 0..99 | Get-Random -Shuffle | ||
| $ouidx = 0..99 | Get-Random -Shuffle | ||
|
|
||
| Write-Output "UserName;GivenName;SurName;UserPrincipalName;DisplayName;Password;Department;Path" > seccoreusers.csv | ||
|
|
||
| foreach ($i in 0..99) { | ||
| $UserName = $FirstName[$fnidx[$i]].ToLower() | ||
| $GivenName = $FirstName[$fnidx[$i]] | ||
| $SurName = $LastName[$lnidx[$i]] | ||
| $UserPrincipalName = $UserName + '@' + 'sec.core' | ||
| $DisplayName = $GivenName + ' ' + $SurName | ||
| $Password = -join ('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ0123456789!#$%&()*+,-./:<=>?@[\]_{|}'.ToCharArray() | Get-Random -Count 16) + '1.aA' | ||
| $Department = ($OrgUnits[$ouidx[$i]] -split '[=,]')[1] | ||
| $Path = $OrgUnits[$ouidx[$i]] + ',' + "dc=SEC,dc=CORE" | ||
| Write-Output "$UserName;$GivenName;$SurName;$UserPrincipalName;$DisplayName;$Password;$Department;$Path" >> seccoreusers.csv | ||
| } |
Oops, something went wrong.