Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Control run fails with an array list as input param when the input is a empty list #2094

Closed
LalitLab opened this issue May 20, 2022 · 2 comments · Fixed by #2108 or #3901
Closed

Control run fails with an array list as input param when the input is a empty list #2094

LalitLab opened this issue May 20, 2022 · 2 comments · Fixed by #2108 or #3901
Assignees
Labels
bug Something isn't working needs review needs planning, discussion or investigation
Milestone

Comments

@LalitLab
Copy link

LalitLab commented May 20, 2022

Describe the bug
I have a compliance mod a below

mod.sp

mod "test_compliance" {
  # hub metadata
  title       = "Test Compliance"
  description = "Test Compliance"
}

variable "allowed_ips" {
  type        = list(string)
  default     = []
  description = "A list of IPs allowed in Snowflake network policies."
}

control "security_overview_network_security_network_policy_allowed_list_set" {
  title       = "Use network policies to allow 'known' client locations (IP ranges)"
  description = "TO DO."
  sql         = <<-EOQ
  with applied_network_policy as (
    select
      'sample' as name,
      array['10.255.255.255', '172.31.255.255', '192.168.255.255'] as allowed_ip_list,
      'test' as account
  ),
  analysis as (
    select
      name,
      to_jsonb ($1::text[]) <@ array_to_json(allowed_ip_list)::jsonb as has_allowed_ips,
      to_jsonb ($1::text[]) - allowed_ip_list as missing_ips,
      account
    from
      applied_network_policy
  )
  select
    -- Required columns
    name as resource,
    case when has_allowed_ips then 'ok' else 'alarm' end as status,
    missing_ips as reason,
    -- Additional columns
    account
  from
    analysis
  EOQ

  param "allowed_ips" {
    default = var.allowed_ips
  }
}
➜  array_input_bug steampipe check all  --var 'allowed_ips=[]'             
Error: runtime error: index out of range [0] with length 0

➜  array_input_bug steampipe check all  --var 'allowed_ips=["10.0.0.0/28"]'

Test Compliance ..................................................................................................................................................................... 0 / 1 [==========]
| 
+ Use network policies to allow 'known' client locations (IP ranges) ................................................................................................................ 0 / 1 [==========]
| | 
| OK   : [] ....................................................................................................................................................................................... test
| 
Summary

OK ...................................................................................................................................................................................... 1 [==========]
SKIP .................................................................................................................................................................................... 0 [          ]
INFO .................................................................................................................................................................................... 0 [          ]
ALARM ................................................................................................................................................................................... 0 [          ]
ERROR ................................................................................................................................................................................... 0 [          ]

TOTAL ............................................................................................................................................................................... 0 / 1 [==========]

Seems like when the list is empty we need to sanitize our input by casting it explicitly. More info in Additional context

Steampipe version (steampipe -v)
Example: v0.14.4

To reproduce

  1. Create a separate folder mkdir test-array-input && cd test-array-input
  2. Create file mod.sp with content specified here mod.txt
  3. Now try below queries:
# Fails
steampipe check all  --var 'allowed_ips=[]'

# Works
steampipe check all  --var 'allowed_ips=["10.0.0.0/28"]'

Expected behavior
Both the queries should work properly

Additional context

PREPARE test_compliance_security_overview_network_security_networ_cc18f AS (          
with applied_network_policy as (                                                      
  select                                                                              
    'sample' as name,                                                                 
    array['10.255.255.255', '172.31.255.255', '192.168.255.255'] as allowed_ip_list,  
    'test' as account                                                                 
),                                                                                    
analysis as (                                                                         
  select                                                                              
    name,                                                                             
    to_jsonb ($1::text[]) <@ array_to_json(allowed_ip_list)::jsonb as has_allowed_ips,
    to_jsonb ($1::text[]) - allowed_ip_list as missing_ips,                           
    account                                                                           
  from                                                                                
    applied_network_policy                                                            
)                                                                                     
select                                                                                
  -- Required columns                                                                 
  name as resource,                                                                   
  case when has_allowed_ips then 'ok' else 'alarm' end as status,                     
  missing_ips as reason,                                                              
  -- Additional columns                                                               
  account                                                                             
from                                                                                  
  analysis                                                                            
)                                                                                     

> execute test_compliance_security_overview_network_security_networ_cc18f(array[])
Error: cannot determine type of empty array (SQLSTATE 42P18)

> execute test_compliance_security_overview_network_security_networ_cc18f(array[]::text[])
+----------+--------+--------+---------+
| resource | status | reason | account |
+----------+--------+--------+---------+
| sample   | ok     | []     | test    |
+----------+--------+--------+---------+

> execute test_compliance_security_overview_network_security_networ_cc18f(array['10.0.0.0/28'])
+----------+--------+-----------------+---------+
| resource | status | reason          | account |
+----------+--------+-----------------+---------+
| sample   | alarm  | ["10.0.0.0/28"] | test    |
+----------+--------+-----------------+---------+
@cbruno10
Copy link
Contributor

cbruno10 commented Apr 28, 2023

@kaidaguerre I'm not sure if this bug is fixed. While using Steampipe CLI v0.19.4, I just tried updating the AWS Perimeter mod, by updating the default value of trusted_accounts (https://github.com/turbot/steampipe-mod-aws-perimeter/blob/18201dc02603b73f7f1db86caa3ddeb0071d4ff9/perimeter/shared_access.sp#L3) to:

variable "trusted_accounts" {
  type        = list(string)
  default     = []
  description = "A list of trusted AWS accounts resources can be shared with."
}

Next I tried running steampipe check control.ebs_snapshot_shared_with_trusted_accounts and received the following error:

+ EBS snapshots should only be shared with trusted accounts ....................................................................................... 1 / 1 [==========]

  ERROR: cannot run aws_perimeter.control.ebs_snapshot_shared_with_trusted_accounts - failed to resolve query "with list_of_snashpot_shared_accounts as (
  select
    jsonb_agg((p -> 'UserId')) as list,
    arn
  from
    aws_ebs_snapshot,
    jsonb_array_elements(create_volume_permissions) as p
  group by arn
), shared_ebs_snapshot as (
  select
    arn,
    list,
    list::jsonb - ($1)::text[] as untrusted_accounts
  from
    list_of_snashpot_shared_accounts
)
select
  s.arn as resource,
  case
    when jsonb_array_length(untrusted_accounts) > 0 then 'info'
    else 'ok'
  end status,
  case
    when s.create_volume_permissions @> '[{"Group": "all"}]'
    then s.title || ' publicly restorable.'
    when jsonb_array_length(untrusted_accounts) > 0 and untrusted_accounts #>> '{0}' != 'all'
    then s.title || ' shared with ' ||
  case
    when jsonb_array_length(untrusted_accounts) > 2
    then concat('untrusted accounts ', untrusted_accounts #>> '{0}', ', ', untrusted_accounts #>> '{1}', ' and ' || (jsonb_array_length(untrusted_accounts) …
    when jsonb_array_length(untrusted_accounts) = 2
    then concat('untrusted accounts ', untrusted_accounts #>> '{0}', ' and ', untrusted_accounts #>> '{1}' , '.')
    else concat('untrusted account ', untrusted_accounts #>> '{0}', '.')
  end
    else
      case when list is null then s.title || ' is not shared.'
      else s.title || ' shared with trusted account(s).' end
  end reason

  , s.region, s.account_id
from
  aws_ebs_snapshot as s left join shared_ebs_snapshot as ss on s.arn = ss.arn ;
": failed to resolve args for aws_perimeter.control.ebs_snapshot_shared_with_trusted_accounts: trusted_accounts

The control is defined as:

control "ebs_snapshot_shared_with_trusted_accounts" {
  title       = "EBS snapshots should only be shared with trusted accounts"
  description = "This control checks whether EBS snapshots access is restricted to trusted accounts."
  sql = <<-EOQ
    with list_of_snashpot_shared_accounts as (
      select
        jsonb_agg((p -> 'UserId')) as list,
        arn
      from
        aws_ebs_snapshot,
        jsonb_array_elements(create_volume_permissions) as p
      group by arn
    ), shared_ebs_snapshot as (
      select
        arn,
        list,
        list::jsonb - ($1)::text[] as untrusted_accounts
      from
        list_of_snashpot_shared_accounts
    )
    select
      s.arn as resource,
      case
        when jsonb_array_length(untrusted_accounts) > 0 then 'info'
        else 'ok'
      end status,
      case
        when s.create_volume_permissions @> '[{"Group": "all"}]'
        then s.title || ' publicly restorable.'
        when jsonb_array_length(untrusted_accounts) > 0 and untrusted_accounts #>> '{0}' != 'all'
        then s.title || ' shared with ' ||
      case
        when jsonb_array_length(untrusted_accounts) > 2
        then concat('untrusted accounts ', untrusted_accounts #>> '{0}', ', ', untrusted_accounts #>> '{1}', ' and ' || (jsonb_array_length(untrusted_accounts) - 2)::text || ' more.' )
        when jsonb_array_length(untrusted_accounts) = 2
        then concat('untrusted accounts ', untrusted_accounts #>> '{0}', ' and ', untrusted_accounts #>> '{1}' , '.')
        else concat('untrusted account ', untrusted_accounts #>> '{0}', '.')
      end
        else
          case when list is null then s.title || ' is not shared.'
          else s.title || ' shared with trusted account(s).' end
      end reason
      ${local.tag_dimensions_sql}
      ${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "s.")}
    from
      aws_ebs_snapshot as s left join shared_ebs_snapshot as ss on s.arn = ss.arn ;
  EOQ
  param "trusted_accounts" {
    description = "A list of trusted accounts."
    default     = var.trusted_accounts
  }
  tags = merge(local.aws_perimeter_common_tags, {
    service = "AWS/EBS"
  })
}

I also tried setting trusted_accounts = [] in my steampipe.spvars file, and received the same error.

Comparatively, if I set the default value or explicit value to something like 123456789012, the control runs as expected.

Are we passing in the trusted_accounts param incorrectly?

@cbruno10 cbruno10 reopened this Apr 28, 2023
@binaek binaek added the needs review needs planning, discussion or investigation label Jun 12, 2023
@github-actions
Copy link

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the stale No recent activity has been detected on this issue/PR and it will be closed label Sep 13, 2023
@kaidaguerre kaidaguerre removed the stale No recent activity has been detected on this issue/PR and it will be closed label Sep 13, 2023
@kaidaguerre kaidaguerre assigned pskrbasu and unassigned kaidaguerre Sep 15, 2023
@kaidaguerre kaidaguerre added this to the 0.21.0 milestone Sep 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs review needs planning, discussion or investigation
Projects
None yet
5 participants