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

RFE: add cloud provider sdk methods to fetch objects (in addition to type=url) #37

Open
amolari opened this issue Jan 19, 2022 · 7 comments
Labels
enhancement New feature or request
Milestone

Comments

@amolari
Copy link

amolari commented Jan 19, 2022

The url type property (in runtime_parameters, extension_services, post_onboard_enables, pre_onboard_enable) results in a simple HTTP get request to fetch scripts, parameters or declarations. I'm asking for the possibility, in addition, to use the cloud-vendor (through its sdk) methods to fetch the refered objects.

Example: with AWS, have a s3 type property with the bucket+key information as parameters.
The request to fetch the object will be executed with, for ex. the s3.getObject method.

Goal: be able to place those scripts, parameters or declarations on a bucket and comply to stricter enterprise policies, such as

  • better ACL/bucket policy definition (using the cloud vendor sdk method, we can use the instance_profile role in the policies)
  • bucket is set to SSE-KMS encryption. Using the instance_profile role, with according policies, the encrypted objects can be fetched.

With the actual code, AFAIK it's not possible to satisfy those requirements
Note: I refer to AWS just because of my prio use-case. However, it makes sense to do the same for all cloud providers.

@shyawnkarim
Copy link

shyawnkarim commented Jan 27, 2022

Thanks for your request. We are now tracking this internally with ID ESECLDTPLT-3051.

@shyawnkarim shyawnkarim added the enhancement New feature or request label Jan 27, 2022
@shyawnkarim shyawnkarim added this to the backlog milestone Jan 27, 2022
@mikeshimkus
Copy link
Contributor

Hi @amolari, this RFE is still in our backlog, but here are examples for all three clouds that will let you download and install AT packages from storage using IAM tokens with the current code:

# aws
controls:
  logLevel: info
  logFilename: /var/log/cloud/bigIpRuntimeInit.log
pre_onboard_enabled: []
runtime_parameters:
  - name: INSTANCE_PROFILE
    type: url
    value: 'http://169.254.169.254/latest/meta-data/iam/security-credentials/'
  - name: TEMPORARY_CREDENTIALS
    type: url
    value: 'http://169.254.169.254/latest/meta-data/iam/security-credentials/{{{INSTANCE_PROFILE}}}'
bigip_ready_enabled:
  - name: download_packages
    type: inline
    commands:
      - "date=\"`date +'%a, %d %b %Y %H:%M:%S %z'`\"; signature_string=\"GET\n\n\n${date}\nx-amz-security-token:{{{TEMPORARY_CREDENTIALS.Token}}}\n/<myBucketName>/<myKey>/f5-appsvcs-templates-1.16.0-1.noarch.rpm\"; signature=`/bin/echo -en \"${signature_string}\" | openssl sha1 -hmac {{{TEMPORARY_CREDENTIALS.SecretAccessKey}}} -binary | base64`; authorization=\"AWS {{{TEMPORARY_CREDENTIALS.AccessKeyId}}}:${signature}\"; curl -s -H \"Date: ${date}\" -H \"X-AMZ-Security-Token: {{{TEMPORARY_CREDENTIALS.Token}}}\" -H \"Authorization: ${authorization}\" \"https://<myBucketName>.s3.amazonaws.com/<myKey>/f5-appsvcs-templates-1.16.0-1.noarch.rpm\" -o /var/config/rest/downloads/f5-appsvcs-templates-1.16.0-1.noarch.rpm"
extension_packages:
  install_operations:
    - extensionType: fast
      extensionVersion: 1.16.0
      extensionUrl: file:///var/config/rest/downloads/f5-appsvcs-templates-1.16.0-1.noarch.rpm
post_onboard_enabled: []

# azure
controls:
  logLevel: info
  logFilename: /var/log/cloud/bigIpRuntimeInit.log
pre_onboard_enabled: []
runtime_parameters:
  - name: ACCESS_TOKEN
    type: url
    query: access_token
    value: 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fstorage.azure.com%2F'
    headers:
      - name: Metadata
        value: true
      - name: x-ms-version
        value: '2017-11-09'
bigip_ready_enabled:
  - name: download_packages
    type: inline
    commands:
      - 'curl https://<myStorageAccountName>.blob.core.windows.net/<myContainerName>/f5-appsvcs-templates-1.16.0-1.noarch.rpm -o /var/config/rest/downloads/f5-appsvcs-templates-1.16.0-1.noarch.rpm -H "x-ms-version:2017-11-09" -H "Authorization: Bearer {{{ACCESS_TOKEN}}}"'
extension_packages:
  install_operations:
    - extensionType: fast
      extensionVersion: 1.16.0
      extensionUrl: file:///var/config/rest/downloads/f5-appsvcs-templates-1.16.0-1.noarch.rpm
post_onboard_enabled: []

# google
controls:
  logLevel: info
  logFilename: /var/log/cloud/bigIpRuntimeInit.log
pre_onboard_enabled: []
runtime_parameters:
  - name: ACCESS_TOKEN
    type: url
    query: access_token
    value: 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/<myServiceAccount>/token'
    headers:
      - name: Metadata-Flavor
        value: Google
bigip_ready_enabled:
  - name: download_packages
    type: inline
    commands:
      - 'curl https://storage.googleapis.com/storage/v1/b/<myBucketName>/f5-appsvcs-templates-1.16.0-1.noarch.rpm -o /var/config/rest/downloads/f5-appsvcs-templates-1.16.0-1.noarch.rpm -H "Authorization: Bearer {{{ACCESS_TOKEN}}}"'
extension_packages:
  install_operations:
    - extensionType: fast
      extensionVersion: 1.16.0
      extensionUrl: file:///var/config/rest/downloads/f5-appsvcs-templates-1.16.0-1.noarch.rpm
post_onboard_enabled: []

@amolari
Copy link
Author

amolari commented Aug 10, 2022

@mikeshimkus
About the GCP use-case I have the issue that the workaround cannot be directly used for the Vault secretProvider.

My declaration has:
  - name: GLOBAL
    type: secret
    verifyTls: true
    secretProvider:
      type: Vault
      environment: hashicorp
      vaultServer: https://vault.xxxxx.com
      appRolePath: /v1/namespace/auth/approle/login
      secretsEngine: kv2
      secretPath: namespace/secret/data/global
      field: data
      version: '1'
      authBackend:
        type: approle
        roleId:
          type: url
          value: https://storage.googleapis.com/storage/v1/b/<myBucketName>/role-id_file
        secretId:
          type: inline
          value: <secret_id>
          unwrap: true

My buckets are not public => auth is required

The issue are in the roleId:

  1. AFAIK there are no header (Authorization Bearer) I could configure here
  2. if point 1 was possible, I guess I cannot rely on another runtime-parameter (in your example ACCESS_TOKEN) ?

At this time my workaround is to fetch the file with curl (auth bearer) locally and point the url value to file:///.
However, I do not like much this approach, as the role-id value is permanent in time (unlike the secret-id) and getting that credential leaked would break the tight security in place.

@mikeshimkus
Copy link
Contributor

mikeshimkus commented Aug 10, 2022

Hi @amolari, according to Vault best practices the role ID isn't considered sensitive, however it makes sense to limit its exposure. If it needs to be treated like a secret, you could store it in Google secrets manager, retrieve it using the secrets provider, and reference the returned value using the "inline" type for roleId instead of "url".

Another option would be to use the metadata runtime parameter time to retrieve it from instance metadata, also using the roleId inline type. Or you could bake it into the image as Hashicorp suggests and use the local file URL.

The internal issue we currently have is for securely downloading files to the device, we would need a new issue for extending that bucket authentication to HTTP requests made by other providers. I will chat with the product owners and report back here.

@mikeshimkus
Copy link
Contributor

@amolari This could work as well:

controls:
  logLevel: info
  logFilename: /var/log/cloud/bigIpRuntimeInit.log
runtime_parameters:
  - name: ACCESS_TOKEN
    type: url
    query: access_token
    value: 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/<myServiceAccount>/token'
    headers:
      - name: Metadata-Flavor
        value: Google
  - name: ROLE_ID
    type: url
    value: 'https://storage.googleapis.com/storage/v1/b/<myBucketName>/role-id_file'
    headers:
      - name: Authorization
        value: Bearer {{{ACCESS_TOKEN}}}
  - name: GLOBAL
    type: secret
    verifyTls: true
    secretProvider:
      type: Vault
      environment: hashicorp
      vaultServer: https://vault.xxxxx.com
      appRolePath: /v1/namespace/auth/approle/login
      secretsEngine: kv2
      secretPath: namespace/secret/data/global
      field: data
      version: '1'
      authBackend:
        type: approle
        roleId:
          type: inline
          value: {{{ROLE_ID}}}
        secretId:
          type: inline
          value: <secret_id>
          unwrap: true

@amolari
Copy link
Author

amolari commented Aug 17, 2022

@mikeshimkus thank you for your answer.
I've tested your proposed workaround and I see:

  1. (syntax): value: {{{ROLE_ID}}} gives the error:
    error: Invalid declaration: "data.runtime_parameters[2].secretProvider.authBackend.roleId.value should be string, data.runtime_parameters[2].secretProvider.authBackend.roleId.value should be string, data.runtime_parameters[2].secretProvider.authBackend.roleId should match "then" schema
  2. no invalid declaration when using value: "{{{ROLE_ID}}}". However, it doesn't get the value => silly: Request response: 400 {"errors":["missing role_id"]}

To find out if this "chaining" of runtime_parameters works, I've set a troubleshooting command in the post_onboard_enabled such as

  - name: troubleshoot
    type: inline
    commands:
      - echo "ACCESS_TOKEN= {{{ ACCESS_TOKEN }}}"
      - echo "ROLE_ID= {{{ ROLE_ID }}}"

the outputed values are correct.

My guess is that refering to another runtime_parameter is not working in the specific type=secret use-case.
Is that the case?
Thank you

@mikeshimkus
Copy link
Contributor

It seems like runtime init only resolves parameters twice, not specifically related to the secret type. In this case it may require three rounds of parameter resolution.

Seems like implementing this as part of a secure downloader would be better, but need to examine that. If part of that were a built-in function to get IAM tokens, I think it would allow you to do this (but would need to be separate from downloader itself, since downloading to the device doesn't work for you).

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

No branches or pull requests

3 participants