{"id":16182574,"url":"https://github.com/jippi/go-metadataproxy","last_synced_at":"2025-03-19T02:30:43.183Z","repository":{"id":29418682,"uuid":"121031298","full_name":"jippi/go-metadataproxy","owner":"jippi","description":"A proxy for AWS's metadata service that gives out scoped IAM credentials from STS","archived":false,"fork":false,"pushed_at":"2023-01-23T04:08:10.000Z","size":331,"stargazers_count":26,"open_issues_count":9,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-11T06:34:01.646Z","etag":null,"topics":["aws","docker","golang","security","sts-credentials"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/jippi/go-metadataproxy/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jippi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-10T16:18:08.000Z","updated_at":"2023-04-28T11:39:54.000Z","dependencies_parsed_at":"2023-02-12T20:15:51.557Z","dependency_job_id":null,"html_url":"https://github.com/jippi/go-metadataproxy","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jippi%2Fgo-metadataproxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jippi%2Fgo-metadataproxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jippi%2Fgo-metadataproxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jippi%2Fgo-metadataproxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jippi","download_url":"https://codeload.github.com/jippi/go-metadataproxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221720281,"owners_count":16869452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","docker","golang","security","sts-credentials"],"created_at":"2024-10-10T06:34:14.139Z","updated_at":"2024-10-27T19:04:48.183Z","avatar_url":"https://github.com/jippi.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-metadataproxy\n\nThe go-metadataproxy is used to allow containers to acquire IAM roles. By metadata we mean [EC2 instance meta data](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) which is normally available to EC2 instances. This proxy exposes the meta data to containers inside or outside of EC2 hosts, allowing you to provide scoped IAM roles to individual containers, rather than giving them the full IAM permissions of an IAM role or IAM user.\n\n## Installation\n\nFrom inside of the repo run the following commands:\n\n```bash\ngo get ./...\ngo install\n```\n\n## Configuration\n\nThe go-metadataproxy has 1 mode of operation, running in AWS where it simply proxies most routes to the real metadata service.\n\n### AWS credentials\n\ngo-metadataproxy relies on AWS Go SDK for its AWS credentials. If metadata\nIAM credentials are available, it will use this. Otherwise, you'll need to use\n.aws/credentials or environment variables to specify the IAM\ncredentials before the service is started.\n\n### Role assumption\n\nFor IAM routes, the go-metadataproxy will use STS to assume roles for containers.\nTo do so it takes the incoming IP address of metadata requests and finds the\nrunning docker container associated with the IP address. It uses the value of\nthe container's `IAM_ROLE` environment variable as the role it will assume. It\nthen assumes the role and gives back STS credentials in the metadata response.\n\nSTS-attained credentials are cached and automatically rotated as they expire.\n\n#### Container-specific roles\n\nTo specify the role of a container, simply launch it with the `IAM_ROLE`\nenvironment variable set to the IAM role you wish the container to run with.\n\n```shell\ndocker run -e IAM_ROLE=my-role ubuntu:14.04\n```\n\n#### Configurable Behavior\n\nThere are a number of environment variables that can be set to tune\nmetadata proxy's behavior. They can either be exported by the start\nscript, or set via docker environment variables.\n\n| Variable | Type | Default | Description |\n| -------- | ---- | ------- | ----------- |\n| `DEFAULT_ROLE` | String | | Role to use if IAM\\_ROLE is not set in a container's environment. If unset the container will get no IAM credentials. |\n| `DEFAULT_ACCOUNT_ID` | String | | The default account ID to assume roles in, if IAM\\_ROLE does not contain account information. If unset, go-metadataproxy will attempt to lookup role ARNs using iam:GetRole. |\n| `LOG_LEVEL` | String | \"info\" | Change the log level (`debug`, `info`, `warning`, `error`, `fatal`, `panic`) |\n| `LOG_FORMAT` | String | \"text\" | Change the log format (`text`, `json`, `gelf`) |\n| `DOCKER_URL` | String | unix://var/run/docker.sock | Url of the docker daemon. The default is to access docker via its socket. |\n| `ROLE_CACHE_OFFSET` | String | | (Optional) Time to substract from Role cache (default: `15m`) (Example: `5m`, `60s`, `5m30s`) |\n| `NEWRELIC_APP_NAME` | String | | (Optional) NewRelic application name. |\n| `NEWRELIC_LICENSE` | String | | (Optional) NewRelic license key. |\n| `COPY_DOCKER_LABELS` | String | | (Optional) a comma separated list of optional case-senstivie Docker labels to copy into telemetry labels. When copied to telemetry label, the string is automatically lower-cased. (example `COPY_DOCKER_LABELS=PROJECT_VERSION,SOMETHING_ELSE`) |\n| `COPY_DOCKER_ENV` | String | | (Optional) a comma separated list of optional case-senstivie Docker env key/value to copy into telemetry labels. When copied to telemetry label, the string is automatically lower-cased. (example `COPY_DOCKER_ENV=PROJECT_VERSION,SOMETHING_ELSE`) |\n| `STATSITE_ADDR` | String | | (Optional) Address for a `statsite` server. |\n| `STATSD_ADDR` | String | | (Optional) Address for a `statsd` server. |\n| `DATADOG_ADDR` | String | | (Optional) Address for a `DataDog statsd` server. |\n| `ENABLE_PROMETHEUS` | Bool | | (Optional) Enable `Prometheus` endpoint. Exposed at `/metrics` endpoint |\n\n#### Telemetry\n\nLabels will be emitted as tags for backends using that.\n\n- `api_version` will be set if for all requests expect `/` (which don't contain the meta-data version in the url path)\n- `handler_name` will be set to the internal method being used to serve the request\n  - `iam-info-handler` will be used for `/{api_version}/meta-data/iam/info`\n  - `iam-security-credentials-name` will be used for `/{api_version}/meta-data/iam/security-credentials/`\n  - `iam-security-crentials-for-role` will be used for `/{api_version}/meta-data/iam/security-credentials/{requested_role}`\n  - `metrics` will be used for `/metrics`\n  - `passthrough` will be used for all other requests\n- `role_name` will be included if go-metadataproxy found a IAM role during the request\n- `request_path` is the full URL path for the request\n- `remote_addr` is the remote address requesting the metadata api (typically the container IP)\n- `response_code` is the response code to the client connecting to go-metadataproxy. All failures result in a `404` code, otherwise `200`\n  - `error_description` If the `response_code` is `404`, this label will contain a description of why - otherwise omitted\n- `service` Always set to `go-metadataproxy`\n\nAdditional labels from `COPY_DOCKER_LABELS` and `COPY_DOCKER_ENV` will be appended to the list above.\n\n| Key | Type | Labels | Description |\n| --- | ---- | ------ | ----------- |\n| `metadataproxy.http_request` | `counter` | `api_version`, `request_path`, `response_code`, `error_description`, `role_name`, `handler_name`, `service` | Emitted for each HTTP request proxied, availbility of the labels depend on the request and AWS response |\n| `metadataproxy.aws_response_time` | `gauage` | `api_version`, `request_path`, `response_code`, `role_name`, `handler_name`, `service` | The full request time (in nanoseconds) when talking to AWS meta-data endpoint. |\n| `metadataproxy.aws_request_time` | `gauge` | `api_version`, `request_path`, `response_code`, `role_name`, `handler_name`, `service` | The request time (in nanoseconds) when talking to AWS meta-data endpoint. |\n| `metadataproxy.aws_connection_time` | `gauge` | `api_version`, `request_path`, `response_code`, `role_name`, `handler_name`, `service` | The connect time (in nanoseconds) when talking to AWS meta-data endpoint. |\n\n#### Default Roles\n\nWhen no role is matched, `go-metadataproxy` will use the role specified in the\n`DEFAULT\\_ROLE` `go-metadataproxy` environment variable. If no DEFAULT\\_ROLE is\nspecified as a fallback, then your docker container without an `IAM\\_ROLE`\nenvironment variable will fail to retrieve credentials.\n\n#### Role Formats\n\nThe following are all supported formats for specifying roles:\n\n- By Role:\n\n    ```shell\n    IAM_ROLE=my-role\n    ```\n\n- By Role@AccountId\n\n    ```shell\n    IAM_ROLE=my-role@012345678910\n    ```\n\n- By ARN:\n\n    ```shell\n    IAM_ROLE=arn:aws:iam::012345678910:role/my-role\n    ```\n\n### Role structure\n\nA useful way to deploy this go-metadataproxy is with a two-tier role\nstructure:\n\n1. The first tier is the EC2 service role for the instances running\n   your containers.  Call it `DockerHostRole`.  Your instances must\n   be launched with a policy that assigns this role.\n\n2. The second tier is the role that each container will use.  These\n   roles must trust your own account (\"Role for Cross-Account\n   Access\" in AWS terms).  Call it `ContainerRole1`.\n\n3. go-metadataproxy needs to query and assume the container role.  So\n   the `DockerHostRole` policy must permit this for each container\n   role.  For example:\n\n   ```json\n    \"Statement\": [ {\n        \"Effect\": \"Allow\",\n        \"Action\": [\n            \"iam:GetRole\",\n            \"sts:AssumeRole\"\n        ],\n        \"Resource\": [\n            \"arn:aws:iam::012345678901:role/ContainerRole1\",\n            \"arn:aws:iam::012345678901:role/ContainerRole2\"\n        ]\n    } ]\n    ```\n\n4. Now customize `ContainerRole1` \u0026 friends as you like\n\nNote: The `ContainerRole1` role should have a trust relationship that allows it to be assumed by the `user` which is associated to the host machine running the `sts:AssumeRole` command.  An example trust relationship for `ContainRole1` may look like:\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"arn:aws:iam::012345678901:root\",\n        \"Service\": \"ec2.amazonaws.com\"\n      },\n      \"Action\": \"sts:AssumeRole\"\n    }\n  ]\n}\n```\n\n### Routing container traffic to go-metadataproxy\n\nUsing iptables, we can forward traffic meant to 169.254.169.254 from docker0 to\nthe go-metadataproxy. The following example assumes the go-metadataproxy is run on\nthe host, and not in a container:\n\n```bash\n/sbin/iptables \\\n  --append PREROUTING \\\n  --destination 169.254.169.254 \\\n  --protocol tcp \\\n  --dport 80 \\\n  --in-interface docker0 \\\n  --jump DNAT \\\n  --table nat \\\n  --to-destination 127.0.0.1:8000 \\\n  --wait\n```\n\nIf you'd like to start the go-metadataproxy in a container, it's recommended to\nuse host-only networking. Also, it's necessary to volume mount in the docker\nsocket, as go-metadataproxy must be able to interact with docker.\n\nBe aware that non-host-mode containers will not be able to contact\n127.0.0.1 in the host network stack.  As an alternative, you can use\nthe meta-data service to find the local address.  In this case, you\nprobably want to restrict proxy access to the docker0 interface!\n\n```bash\nLOCAL_IPV4=$(curl http://169.254.169.254/latest/meta-data/local-ipv4)\n\n/sbin/iptables \\\n  --append PREROUTING \\\n  --destination 169.254.169.254 \\\n  --protocol tcp \\\n  --dport 80 \\\n  --in-interface docker0 \\\n  --jump DNAT \\\n  --table nat \\\n  --to-destination $LOCAL_IPV4:8000 \\\n  --wait\n\n/sbin/iptables \\\n  --wait \\\n  --insert INPUT 1 \\\n  --protocol tcp \\\n  --dport 80 \\\n  \\! \\\n  --in-interface docker0 \\\n  --jump DROP\n```\n\nIf you run Docker containers within their own bridge network, the network interface will be in format `br-\u003cnetwork-id\u003e` rather than `docker0`.\n\nFor example, if a Docker network is created:\n\n```bash\ndocker network create some-network\nd180d436e9c4c4322156140ba04233a530a30966ddbcd7f9be4331724d78f459\n```\n\nYou may have network interface `br-d180d436e9c4`.\n\nYou can setup `iptables` to forward traffic from any such bridge network with a wildcard `+`:\n\n```bash\nLOCAL_IPV4=$(curl http://169.254.169.254/latest/meta-data/local-ipv4)\n\n/sbin/iptables \\\n  --append PREROUTING \\\n  --destination 169.254.169.254 \\\n  --protocol tcp \\\n  --dport 80 \\\n  --in-interface br-+ \\\n  --jump DNAT \\\n  --table nat \\\n  --to-destination $LOCAL_IPV4:8000 \\\n  --wait\n```\n\n## Run go-metadataproxy without docker\n\nIn the following we assume \\_my\\_config\\_ is a bash file with exports for all of\nthe necessary settings discussed in the configuration section.\n\n```bash\nsource my_config\ncd /srv/go-metadataproxy\ngo run main.go\n```\n\n## Run go-metadataproxy with docker\n\nFor production purposes, you'll want to kick up a container to run.\nYou can build one with the included Dockerfile.  To run, do something like:\n\n```bash\ndocker run --net=host \\\n    -v /var/run/docker.sock:/var/run/docker.sock \\\n    jippi/go-metadataproxy\n```\n\n## Attribution\n\nThis project is a ~1:1 port of [lyft/metadataproxy](https://github.com/lyft/metadataproxy), done in Go.\n\n## Contributing\n\n### File issues in Github\n\nIn general all enhancements or bugs should be tracked via github issues before\nPRs are submitted. We don't require them, but it'll help us plan and track.\n\nWhen submitting bugs through issues, please try to be as descriptive as\npossible. It'll make it easier and quicker for everyone if the developers can\neasily reproduce your bug.\n\n### Submit pull requests\n\nOur only method of accepting code changes is through github pull requests.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjippi%2Fgo-metadataproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjippi%2Fgo-metadataproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjippi%2Fgo-metadataproxy/lists"}