public/container-security.ps1

function Edit-FalconContainerRegistry {
<#
.SYNOPSIS
Modify a registry within Falcon Container Security
.DESCRIPTION
Requires 'Falcon Container Image: Write'.
.PARAMETER Name
Falcon Container Security registry name
.PARAMETER State
Registry connection state
.PARAMETER Credential
A hashtable containing credentials to access the registry
.PARAMETER Id
Container registry identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerRegistry
#>

  [CmdletBinding(DefaultParameterSetName='/container-security/entities/registries/v1:patch',
    SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=1)]
    [Alias('user_defined_alias')]
    [string]$Name,
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=2)]
    [ValidateSet('pause','resume',IgnoreCase=$false)]
    [string]$State,
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=3)]
    [hashtable]$Credential,
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Mandatory,
      ValueFromPipelineByPropertyName,ValueFromPipeline,Position=4)]
    [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
    [string]$Id
  )
  begin {
    $Param = @{
      Command = $MyInvocation.MyCommand.Name
      Endpoint = $PSCmdlet.ParameterSetName
      Format = @{
        Body = @{ root = @('credential','user_defined_alias','state') }
        Query = @('id')
      }
    }
  }
  process {
    if ($PSBoundParameters.Credential) {
      $PSBoundParameters.Credential = @{ details = $PSBoundParameters.Credential }
    }
    Invoke-Falcon @Param -UserInput $PSBoundParameters
  }
}
function Get-FalconContainerAssessment {
<#
.SYNOPSIS
Retrieve Falcon container image assessment reports
.DESCRIPTION
Requires 'Falcon Container Image: Write'.
.PARAMETER Registry
Container registry
.PARAMETER Repository
Container repository
.PARAMETER Tag
Container tag
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAssessment
#>

  [CmdletBinding(DefaultParameterSetName='/reports:get',SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/reports:get',Mandatory,Position=1)]
    [string]$Registry,
    [Parameter(ParameterSetName='/reports:get',Mandatory,Position=2)]
    [string]$Repository,
    [Parameter(ParameterSetName='/reports:get',Mandatory,Position=3)]
    [string]$Tag
  )
  begin {
    $Param = @{
      Command = $MyInvocation.MyCommand.Name
      Endpoint = $PSCmdlet.ParameterSetName
      Format = @{ Query = @('registry','repository','tag') }
      HostUrl = Get-ContainerUrl
    }
  }
  process {
    $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters
    try { $Request | ConvertFrom-Json } catch { $Request }
  }
}
function Get-FalconContainerRegistry {
<#
.SYNOPSIS
List Falcon Container Security registries
.DESCRIPTION
Requires 'Falcon Container Image: Read'.
.PARAMETER Id
Container registry identifier
.PARAMETER Sort
Property and direction to sort results
.PARAMETER Limit
Maximum number of results per request
.PARAMETER Offset
Position to begin retrieving results
.PARAMETER Detailed
Retrieve detailed information
.PARAMETER All
Repeat requests until all available results are retrieved
.PARAMETER Total
Display total result count instead of results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerRegistry
#>

  [CmdletBinding(DefaultParameterSetName='/container-security/queries/registries/v1:get',SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:get',Mandatory,
      ValueFromPipelineByPropertyName,ValueFromPipeline)]
    [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
    [Alias('ids')]
    [string]$Id,
    [Parameter(ParameterSetName='/container-security/queries/registries/v1:get',Position=1)]
    [string]$Sort,
    [Parameter(ParameterSetName='/container-security/queries/registries/v1:get',Position=2)]
    [int]$Limit,
    [Parameter(ParameterSetName='/container-security/queries/registries/v1:get')]
    [int]$Offset,
    [Parameter(ParameterSetName='/container-security/queries/registries/v1:get')]
    [switch]$Detailed,
    [Parameter(ParameterSetName='/container-security/queries/registries/v1:get')]
    [switch]$All,
    [Parameter(ParameterSetName='/container-security/queries/registries/v1:get')]
    [switch]$Total
  )
  begin {
    $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }
    [System.Collections.Generic.List[string]]$List = @()
  }
  process { if ($Id) { @($Id).foreach{ $List.Add($_) }}}
  end {
    if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) }
    Invoke-Falcon @Param -UserInput $PSBoundParameters
  }
}
function Get-FalconContainerSensor {
<#
.SYNOPSIS
Retrieve the most recent Falcon container sensor build tags
.DESCRIPTION
Requires 'Falcon Container Image: Read'.
.PARAMETER LatestUrl
Create a URL using the most recent build tag
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerSensor
#>

  [CmdletBinding(DefaultParameterSetName='/v2/{sensortype}/{region}/release/falcon-sensor/tags/list:get',
    SupportsShouldProcess)]
  param([switch]$LatestUrl)
  process {
    if (!$Script:Falcon.Registry -or $Script:Falcon.Registry.Expiration -lt (Get-Date).AddSeconds(240)) {
      Request-FalconRegistryCredential
    }
    $Param = @{
      Endpoint = $PSCmdlet.ParameterSetName -replace '{sensortype}',
        $Script:Falcon.Registry.SensorType -replace '{region}',$Script:Falcon.Registry.Region
      Header = @{ Authorization = "Bearer $($Script:Falcon.Registry.Token)" }
      HostUrl = Get-ContainerUrl -Registry
    }
    $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters
    $Result = try { $Request | ConvertFrom-Json } catch { $Request }
    if ($LatestUrl) {
      ($Param.HostUrl -replace 'https://',$null),$Script:Falcon.Registry.SensorType,
        $Script:Falcon.Registry.Region,'release',"falcon-sensor:$($Result.tags[-1])" -join '/'
    } else {
      $Result
    }
  }
}
function New-FalconContainerRegistry {
<#
.SYNOPSIS
Create a registry within Falcon Container Security
.DESCRIPTION
Requires 'Falcon Container Image: Write'.
.PARAMETER Name
Desired registry name within Falcon Container Security
.PARAMETER Type
Registry type
.PARAMETER Url
URL used to log in to the registry
.PARAMETER Credential
A hashtable containing credentials to access the registry
.PARAMETER UrlUniquenessKey
Registry URL alias
 
Available with Docker Hub, Google Artifact Registry, Google Container Registry, IBM Cloud, and Oracle
.LINK
https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerRegistry
#>

  [CmdletBinding(DefaultParameterSetName='/container-security/entities/registries/v1:post',
    SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:post',Mandatory,Position=1)]
    [Alias('user_defined_alias')]
    [string]$Name,
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:post',Mandatory,Position=2)]
    [ValidateSet('acr','artifactory','docker','dockerhub','ecr','gar','gcr','github','gitlab','harbor','icr',
      'mirantis','nexus','openshift','oracle','quay.io',IgnoreCase=$false)]
    [string]$Type,
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:post',Mandatory,Position=3)]
    [string]$Url,
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:post',Mandatory,Position=4)]
    [hashtable]$Credential,
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:post',Position=5)]
    [Alias('url_uniqueness_key')]
    [string]$UrlUniquenessKey
  )
  begin {
    $Param = @{
      Command = $MyInvocation.MyCommand.Name
      Endpoint = $PSCmdlet.ParameterSetName
      Format = @{ Body = @{ root = @('credential','user_defined_alias','url','url_uniqueness_key','type') }}
    }
  }
  process {
    $PSBoundParameters.Credential = @{ details = $PSBoundParameters.Credential }
    Invoke-Falcon @Param -UserInput $PSBoundParameters
  }
}
function Remove-FalconContainerImage {
<#
.SYNOPSIS
Remove a Falcon container image
.DESCRIPTION
Requires 'Falcon Container Image: Write'.
.PARAMETER Id
Container image identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerImage
#>

  [CmdletBinding(DefaultParameterSetName='/images/{id}:delete',SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/images/{id}:delete',Mandatory,ValueFromPipelineByPropertyName,
      ValueFromPipeline,Position=1)]
    [object]$Id
  )
  begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; HostUrl = Get-ContainerUrl }}
  process {
    $PSBoundParameters.Id = switch ($PSBoundParameters.Id) {
      { $_.ImageInfo.id } { $_.ImageInfo.id }
      { $_ -is [string] } { $_ }
    }
    if ($PSBoundParameters.Id -notmatch '^[A-Fa-f0-9]{64}$') {
      throw "'$($PSBoundParameters.Id)' is not a valid image identifier."
    } else {
      $Endpoint = $PSCmdlet.ParameterSetName -replace '{id}',$PSBoundParameters.Id
      [void]$PSBoundParameters.Remove('Id')
      Invoke-Falcon @Param -Endpoint $Endpoint -UserInput $PSBoundParameters
    }
  }
}
function Remove-FalconContainerRegistry {
<#
.SYNOPSIS
Remove a registry from Falcon Container Security
.DESCRIPTION
Requires 'Falcon Container Image: Write'.
.PARAMETER Id
Container registry identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerRegistry
#>

  [CmdletBinding(DefaultParameterSetName='/container-security/entities/registries/v1:delete',
    SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/container-security/entities/registries/v1:delete',Mandatory,
      ValueFromPipelineByPropertyName,ValueFromPipeline)]
    [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
    [Alias('ids')]
    [string]$Id
  )
  begin {
    $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }
    [System.Collections.Generic.List[string]]$List = @()
  }
  process { if ($Id) { @($Id).foreach{ $List.Add($_) }}}
  end {
    if ($List) {
      $PSBoundParameters['Id'] = @($List | Select-Object -Unique)
      Invoke-Falcon @Param -UserInput $PSBoundParameters
    }
  }
}
function Remove-FalconRegistryCredential {
<#
.SYNOPSIS
Remove your cached Falcon container registry access token and credential information from the module
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconRegistryCredential
#>

  [CmdletBinding(SupportsShouldProcess)]
  param()
  process { if ($Script:Falcon.Registry) { [void]$Script:Falcon.Remove('Registry') }}
}
function Request-FalconRegistryCredential {
<#
.SYNOPSIS
Request your Falcon container registry username, password and access token
.DESCRIPTION
If successful, you token and username are cached for re-use as you use Falcon container security related commands.
 
If an active access token is due to expire in less than 15 seconds, a new token will automatically be requested.
 
Requires 'Falcon Container Image: Read' and 'Sensor Download: Read'.
.PARAMETER SensorType
Container sensor type, used to determine container registry
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Request-FalconRegistryCredential
#>

  [CmdletBinding(SupportsShouldProcess)]
  param(
    [Parameter(Mandatory,Position=1)]
    [ValidateSet('falcon-sensor','falcon-container',IgnoreCase=$false)]
    [string]$SensorType
  )
  process {
    [System.Collections.Hashtable]$Credential = @{}
    $Credential['Username'] = if ($Script:Falcon.Registry.Username) {
      $Script:Falcon.Registry.Username
    } else {
      try {
        @(Get-FalconCcid -EA 0).foreach{ 'fc',$_.Split('-')[0].ToLower() -join '-' }
      } catch {
        throw "Failed to retrieve registry username. Verify 'Sensor Download: Read' permission."
      }
    }
    $Credential['Password'] = if ($Script:Falcon.Registry.Password) {
      $Script:Falcon.Registry.Password
    } else {
      try {
        (Invoke-Falcon -Endpoint (
          '/container-security/entities/image-registry-credentials/v1:get')).Token
      } catch {
        throw "Failed to retrieve registry password. Verify 'Falcon Container Image: Read' permission."
      }
    }
    if ($Credential.Username -and $Credential.Password) {
      $Param = @{
        Endpoint = "/v2/token?=$($Credential.Username):get"
        Header = @{
          Authorization = "Basic $([System.Convert]::ToBase64String(
            [System.Text.Encoding]::ASCII.GetBytes("$($Credential.Username):$(
              $Credential.Password)")))"

        }
        Format = @{ Query = @('scope','service') }
        HostUrl = Get-ContainerUrl -Registry
      }
      [string]$Region = switch -Regex ($Script:Falcon.Hostname) {
        'eu-1'    { 'eu-1' }
        'laggar\.gcw' { 'us-gov-1' }
        'us-2'    { 'us-2' }
        default     { 'us-1' }
      }
      $PSBoundParameters['scope'] = 'repository:',"/$Region/release/",':pull' -join
        $PSBoundParameters.SensorType
      $PSBoundParameters['service'] = 'registry.crowdstrike.com'
      [void]$PSBoundParameters.Remove('SensorType')
      $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters
      if ($Request) {
        $Script:Falcon['Registry'] = @{
          Username = $Credential.Username
          Password = $Credential.Password
          Region = $Region
          SensorType = $SensorType
          Token = $Request.token
          Expiration = (Get-Date).AddSeconds($Request.expires_in)
        }
      }
    }
  }
}
function Show-FalconRegistryCredential {
<#
.SYNOPSIS
Display Falcon container registry credential information
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Show-FalconRegistryCredential
#>

  [CmdletBinding()]
  param()
  process {
    if ($Script:Falcon.Registry) {
      [string]$PullToken = if ($Script:Falcon.Registry.Username -and $Script:Falcon.Registry.Password) {
        [string]$BaseAuth = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$(
          $Script:Falcon.Registry.Username):$($Script:Falcon.Registry.Password)"
))
        [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$([PSCustomObject]@{
          auths = @{ 'registry.crowdstrike.com' = @{ auth = $BaseAuth }}} | ConvertTo-Json -Depth 4)"
))
      }
      [PSCustomObject]@{
        Token = if ($Script:Falcon.Registry.Token -and $Script:Falcon.Registry.Expiration -gt
        (Get-Date).AddSeconds(240)) {
          $true
        } else {
          $false
        }
        Username = $Script:Falcon.Registry.Username
        Password = $Script:Falcon.Registry.Password
        Region = $Script:Falcon.Registry.Region
        SensorType = $Script:Falcon.Registry.SensorType
        PullToken = $PullToken
      }
    } else {
      Write-Error "No registry credential available. Try 'Request-FalconRegistryCredential'."
    }
  }
}