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

default_iam_policy does not correctly include VPC related actions on resource creation #499

Closed
3 tasks done
heythisisnate opened this issue Jun 23, 2020 · 3 comments
Closed
3 tasks done

Comments

@heythisisnate
Copy link
Contributor

heythisisnate commented Jun 23, 2020

Checklist

  • Upgrade Jets: Are you using the latest version of Jets? This allows Jets to fix issues fast. There's a jets upgrade command that makes this a simple task. There's also an Upgrading Guide: http://rubyonjets.com/docs/upgrading/
  • Reproducibility: Are you reporting a bug others will be able to reproduce and not asking a question. If you're unsure or want to ask a question, do so on https://community.rubyonjets.com
  • Code sample: Have you put together a code sample to reproduce the issue and make it available? Code samples help speed up fixes dramatically. If it's an easily reproducible issue, then code samples are not needed. If you're unsure, please include a code sample.

My Environment

Software Version
Operating System Mac OS
Jets 2.3.16
Ruby 2.5.3

I have a vpc_config defined in the production environment only. In production.rb:

vpc_config = {
    'us-east-1' => {
      security_group_ids: %w{ sg-xxxxxx },
      subnet_ids: %w{ subnet-aaaaaa subnet-bbbbbb subnet-cccccc }
    },
    'eu-west-1' => {
      security_group_ids: %w{ sg-yyyyyy },
      subnet_ids: %w{ subnet-dddddd subnet-eeeeee subnet-ffffff }
    },
    'ap-northeast-1' => {
      security_group_ids: %w{ sg-zzzzzz },
      subnet_ids: %w{ subnet-gggggg subnet-hhhhhh subnet-iiiiii }
    }
  }

  config.function.vpc_config = {
    security_group_ids: vpc_config[Jets.aws.region][:security_group_ids],
    subnet_ids: vpc_config[Jets.aws.region][:subnet_ids]
  }

Expected Behaviour

jets deploy should be able to create a new Lambda resource and connect it to the configured VPC

Current Behavior

Resource creation fails in CloudFormation with an error related to missing the ec2:CreateNetworkInterface pemission.

Step-by-step reproduction instructions

Define Jets.config.function.vpc_config in production.rb or in a specific environment and deploy a new Lambda resource (such as a Jets controller) using jets deploy. Resource creation will fail.

Code Sample

Solution Suggestion

The problem seems to originate from:
https://github.com/tongueroo/jets/blob/master/lib/jets/application/defaults.rb#L33-L47

       if Jets.config.function.vpc_config
          vpc = {
            action: %w[
              ec2:CreateNetworkInterface
              ec2:DeleteNetworkInterface
              ec2:DescribeNetworkInterfaces
              ec2:DescribeVpcs
              ec2:DescribeSubnets
              ec2:DescribeSecurityGroups
            ],
            effect: "Allow",
            resource: "*",
          }
          policies << vpc
        end

When running the jets deploy task, this section of code gets executed twice. It appears that on the first execution, the conditional does not return true, so these VPC related actions are not added to the default policies. I couldn't figure out why this occurs. My presumption is that the production.rb environment is not loaded locally when the jets deploy task is creating a new resource.

Workaround: comment out the conditional if Jets.config.function.vpc_config ... end in the above code block locally, then deploy.

I'd be happy to try to propose a fix, but I'm not sure why this is being loaded twice, once without the production environment variables loaded. Any guidance would be appreciated!

@heythisisnate
Copy link
Contributor Author

I dug into this a little more. The problem has to do with a race condition in my configuration
I'm trying to append the global IAM policy to allow lambda:InvokeFunction. In application.rb:

  config.iam_policy = [
    Jets::Application.default_iam_policy,
    {
      action: %w{ lambda:invokeFunction },
      effect: 'Allow',
      resource: "arn:aws:lambda:#{Jets.aws.region}:#{Jets.aws.account}:function:#{Jets::Naming.parent_stack_name}-*"
    }
  ]

The problem that I just realized is that calling Jets::Application.default_iam_policy here creates a race condition where the default policy is generated before the correct environment is loaded.

I'm currently looking for other ways to cleanly append to default_iam_policy without the race condition. @tongueroo any ideas?

@heythisisnate
Copy link
Contributor Author

Got something that I think works. The goal is to cleanly append to default_iam_policy without causing the env loading race condition. I modified application.rb as follows:

Jets.application.config do
  # config.iam_policy = []   # this is commented out so defaults apply
  ...
end

module MyDefaults
  def default_iam_policy
    super << {
      action: %w{ lambda:invokeFunction },
      effect: 'Allow',
      resource: "arn:aws:lambda:#{Jets.aws.region}:#{Jets.aws.account}:function:#{Jets.project_namespace}-*"
    }
  end
end

Jets::Application.singleton_class.prepend MyDefaults

It wasn't obvious how to use prepend with a class method. Took a bit of searching and experimentation to make this work. Might be useful for the docs?

@tongueroo
Copy link
Collaborator

Thanks for reporting this. This was handled by #457

Tested specifically your examples. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants