Skip to content

Refactor workflow for RDP and Tailscale#1

Open
mdabdulaziz123 wants to merge 1 commit into
RojanSapkota:mainfrom
mdabdulaziz123:patch-1
Open

Refactor workflow for RDP and Tailscale#1
mdabdulaziz123 wants to merge 1 commit into
RojanSapkota:mainfrom
mdabdulaziz123:patch-1

Conversation

@mdabdulaziz123
Copy link
Copy Markdown

No description provided.

@mdabdulaziz123
Copy link
Copy Markdown
Author

name: RDP

on:
workflow_dispatch:

jobs:
secure-rdp:
runs-on: windows-latest
timeout-minutes: 3600

steps:
  - name: Configure Core RDP Settings
    run: |
      # Enable Remote Desktop and disable Network Level Authentication (if needed)
      Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' `
                         -Name "fDenyTSConnections" -Value 0 -Force
      Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
                         -Name "UserAuthentication" -Value 0 -Force
      Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
                         -Name "SecurityLayer" -Value 0 -Force

      # Remove any existing rule with the same name to avoid duplication
      netsh advfirewall firewall delete rule name="RDP-Tailscale"
      
      # For testing, allow any incoming connection on port 3389
      netsh advfirewall firewall add rule name="RDP-Tailscale" `
        dir=in action=allow protocol=TCP localport=3389

      # (Optional) Restart the Remote Desktop service to ensure changes take effect
      Restart-Service -Name TermService -Force

  - name: Create RDP User with Secure Password
    run: |
      Add-Type -AssemblyName System.Security
      $charSet = @{
          Upper   = [char[]](65..90)      # A-Z
          Lower   = [char[]](97..122)     # a-z
          Number  = [char[]](48..57)      # 0-9
          Special = ([char[]](33..47) + [char[]](58..64) +
                     [char[]](91..96) + [char[]](123..126)) # Special characters
      }
      $rawPassword = @()
      $rawPassword += $charSet.Upper | Get-Random -Count 4
      $rawPassword += $charSet.Lower | Get-Random -Count 4
      $rawPassword += $charSet.Number | Get-Random -Count 4
      $rawPassword += $charSet.Special | Get-Random -Count 4
      $password = -join ($rawPassword | Sort-Object { Get-Random })
      $securePass = ConvertTo-SecureString $password -AsPlainText -Force
      New-LocalUser -Name "RDP" -Password $securePass -AccountNeverExpires
      Add-LocalGroupMember -Group "Administrators" -Member "RDP"
      Add-LocalGroupMember -Group "Remote Desktop Users" -Member "RDP"
      
      echo "RDP_CREDS=User: RDP | Password: $password" >> $env:GITHUB_ENV
      
      if (-not (Get-LocalUser -Name "RDP")) {
          Write-Error "User creation failed"
          exit 1
      }

  - name: Install Tailscale
    run: |
      $tsUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-1.82.0-amd64.msi"
      $installerPath = "$env:TEMP\tailscale.msi"
      
      Invoke-WebRequest -Uri $tsUrl -OutFile $installerPath
      Start-Process msiexec.exe -ArgumentList "/i", "`"$installerPath`"", "/quiet", "/norestart" -Wait
      Remove-Item $installerPath -Force

  - name: Establish Tailscale Connection
    run: |
      # Bring up Tailscale with the provided auth key and set a unique hostname
      & "$env:ProgramFiles\Tailscale\tailscale.exe" up --authkey=${{ secrets.TAILSCALE_AUTH_KEY }} --hostname=gh-runner-$env:GITHUB_RUN_ID
      
      # Wait for Tailscale to assign an IP
      $tsIP = $null
      $retries = 0
      while (-not $tsIP -and $retries -lt 10) {
          $tsIP = & "$env:ProgramFiles\Tailscale\tailscale.exe" ip -4
          Start-Sleep -Seconds 5
          $retries++
      }
      
      if (-not $tsIP) {
          Write-Error "Tailscale IP not assigned. Exiting."
          exit 1
      }
      echo "TAILSCALE_IP=$tsIP" >> $env:GITHUB_ENV
  
  - name: Verify RDP Accessibility
    run: |
      Write-Host "Tailscale IP: $env:TAILSCALE_IP"
      
      # Test connectivity using Test-NetConnection against the Tailscale IP on port 3389
      $testResult = Test-NetConnection -ComputerName $env:TAILSCALE_IP -Port 3389
      if (-not $testResult.TcpTestSucceeded) {
          Write-Error "TCP connection to RDP port 3389 failed"
          exit 1
      }
      Write-Host "TCP connectivity successful!"

  - name: Maintain Connection
    run: |
      Write-Host "`n=== RDP ACCESS ==="
      Write-Host "Address: $env:TAILSCALE_IP"
      Write-Host "Username: RDP"
      Write-Host "Password: $(echo $env:RDP_CREDS)"
      Write-Host "==================`n"
      
      # Keep runner active indefinitely (or until manually cancelled)
      while ($true) {
          Write-Host "[$(Get-Date)] RDP Active - Use Ctrl+C in workflow to terminate"
          Start-Sleep -Seconds 300
      }

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the GitHub Actions workflow to establish a secure RDP connection using Tailscale instead of ngrok, with improved security controls and connection management.

  • Replaces ngrok tunneling with Tailscale VPN for more secure remote access
  • Implements dynamic password generation for the RDP user instead of a hardcoded password
  • Adds comprehensive RDP configuration, firewall rules, and connection verification steps

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

New-LocalUser -Name "RDP" -Password $securePass -AccountNeverExpires
Add-LocalGroupMember -Group "Administrators" -Member "RDP"
Add-LocalGroupMember -Group "Remote Desktop Users" -Member "RDP"

Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The password is being echoed to GITHUB_ENV in plain text and then displayed in the logs at line 106. This creates a security vulnerability as the password will be visible in the workflow logs. Consider using GitHub Actions secrets or masking the password output using ::add-mask:: before echoing it to prevent exposure in logs.

Suggested change
Write-Output "::add-mask::$password"

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +20
-Name "UserAuthentication" -Value 0 -Force
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
-Name "SecurityLayer" -Value 0 -Force
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Network Level Authentication (NLA) is being disabled (UserAuthentication=0) and SecurityLayer is set to 0, which weakens RDP security significantly. This configuration allows unauthenticated connections and removes encryption negotiation, making the connection vulnerable to man-in-the-middle attacks. Consider keeping NLA enabled (Value 1) unless there's a specific requirement to disable it, especially since this is exposed over a network connection.

Suggested change
-Name "UserAuthentication" -Value 0 -Force
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
-Name "SecurityLayer" -Value 0 -Force
-Name "UserAuthentication" -Value 1 -Force
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
-Name "SecurityLayer" -Value 2 -Force

Copilot uses AI. Check for mistakes.
Comment on lines +70 to +72
run: |
# Bring up Tailscale with the provided auth key and set a unique hostname
& "$env:ProgramFiles\Tailscale\tailscale.exe" up --authkey=${{ secrets.TAILSCALE_AUTH_KEY }} --hostname=gh-runner-$env:GITHUB_RUN_ID
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Tailscale auth key is being passed directly in the command line, which may be visible in process listings and logs. Consider using an environment variable with masking or a more secure method to pass the auth key to avoid exposure in logs and process tables.

Suggested change
run: |
# Bring up Tailscale with the provided auth key and set a unique hostname
& "$env:ProgramFiles\Tailscale\tailscale.exe" up --authkey=${{ secrets.TAILSCALE_AUTH_KEY }} --hostname=gh-runner-$env:GITHUB_RUN_ID
env:
TS_AUTHKEY: ${{ secrets.TAILSCALE_AUTH_KEY }}
run: |
# Bring up Tailscale with the provided auth key and set a unique hostname
& "$env:ProgramFiles\Tailscale\tailscale.exe" up --hostname=gh-runner-$env:GITHUB_RUN_ID

Copilot uses AI. Check for mistakes.

secure-rdp:
runs-on: windows-latest
timeout-minutes: 3600
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timeout is set to 3600 minutes (60 hours), which exceeds GitHub Actions' maximum job execution time limit of 6 hours (360 minutes) for standard runners. This will cause the job to fail when it hits the platform limit. Consider setting this to 360 or less to align with GitHub Actions constraints.

Suggested change
timeout-minutes: 3600
timeout-minutes: 360

Copilot uses AI. Check for mistakes.
Write-Host "`n=== RDP ACCESS ==="
Write-Host "Address: $env:TAILSCALE_IP"
Write-Host "Username: RDP"
Write-Host "Password: $(echo $env:RDP_CREDS)"
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The password extraction from RDP_CREDS using echo $env:RDP_CREDS will display the entire string "User: RDP | Password: [password]" rather than just the password. This seems inconsistent with lines 104-105 which display the username and address separately. Consider storing just the password in the environment variable, or parse it properly when displaying.

Suggested change
Write-Host "Password: $(echo $env:RDP_CREDS)"
Write-Host "Password: $((($env:RDP_CREDS -split 'Password: ')[-1]).Trim())"

Copilot uses AI. Check for mistakes.

- name: Install Tailscale
run: |
$tsUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-1.82.0-amd64.msi"
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using a hardcoded Tailscale version (1.82.0) may cause issues if this version becomes unavailable or deprecated. Consider using the "latest" stable release URL or documenting why this specific version is required. The URL pattern could be https://pkgs.tailscale.com/stable/tailscale-setup-latest-amd64.msi for automatic updates.

Suggested change
$tsUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-1.82.0-amd64.msi"
$tsUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-latest-amd64.msi"

Copilot uses AI. Check for mistakes.
Write-Host "`n=== RDP ACCESS ==="
Write-Host "Address: $env:TAILSCALE_IP"
Write-Host "Username: RDP"
Write-Host "Password: $(echo $env:RDP_CREDS)"
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The password stored in RDP_CREDS is being directly echoed to the console logs, which exposes the sensitive credential. This is a security risk as anyone with access to the workflow logs can see the password. Use Add-Content $env:GITHUB_STEP_SUMMARY instead to display credentials only in the job summary, or use ::add-mask:: to mask the password value.

Suggested change
Write-Host "Password: $(echo $env:RDP_CREDS)"
Add-Content $env:GITHUB_STEP_SUMMARY "`n=== RDP ACCESS ===`nAddress: $env:TAILSCALE_IP`nUsername: RDP`nPassword: $env:RDP_CREDS`n==================`n"

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +58
echo "RDP_CREDS=User: RDP | Password: $password" >> $env:GITHUB_ENV

if (-not (Get-LocalUser -Name "RDP")) {
Write-Error "User creation failed"
exit 1
}
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user verification check occurs after the password has already been written to GITHUB_ENV. If user creation fails, the workflow will exit but the environment variable with the password will have already been set in previous steps' logs. Move this validation before writing credentials to the environment to prevent potential credential leakage on failure.

Suggested change
echo "RDP_CREDS=User: RDP | Password: $password" >> $env:GITHUB_ENV
if (-not (Get-LocalUser -Name "RDP")) {
Write-Error "User creation failed"
exit 1
}
if (-not (Get-LocalUser -Name "RDP")) {
Write-Error "User creation failed"
exit 1
}
echo "RDP_CREDS=User: RDP | Password: $password" >> $env:GITHUB_ENV

Copilot uses AI. Check for mistakes.
-Name "SecurityLayer" -Value 0 -Force

# Remove any existing rule with the same name to avoid duplication
netsh advfirewall firewall delete rule name="RDP-Tailscale"
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The firewall rule deletion command will display an error if the rule doesn't exist on first run. Consider adding error suppression or a conditional check to prevent unnecessary error output: netsh advfirewall firewall delete rule name="RDP-Tailscale" 2>$null or check for rule existence first.

Suggested change
netsh advfirewall firewall delete rule name="RDP-Tailscale"
netsh advfirewall firewall delete rule name="RDP-Tailscale" 2>$null

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants