Skip to content

Commit

Permalink
aws: Refactor IMDSv2 support additions
Browse files Browse the repository at this point in the history
Signed-off-by: Matthew Fala <[email protected]>
  • Loading branch information
matthewfala committed Sep 21, 2021
1 parent dba9c06 commit fa844ec
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 250 deletions.
57 changes: 31 additions & 26 deletions include/fluent-bit/aws/flb_aws_imds.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,28 @@
#ifndef FLB_AWS_IMDS
#define FLB_AWS_IMDS

#define FLB_AWS_IMDS_HOST "169.254.169.254"
#define FLB_AWS_IMDS_HOST_LEN 15
#define FLB_AWS_IMDS_PORT 80
#define FLB_AWS_IMDS_HOST "169.254.169.254"
#define FLB_AWS_IMDS_HOST_LEN 15
#define FLB_AWS_IMDS_PORT 80

#define FLB_AWS_IMDS_VERSION_EVALUATE 0
#define FLB_AWS_IMDS_VERSION_1 1
#define FLB_AWS_IMDS_VERSION_2 2
#define FLB_AWS_IMDS_VERSION_EVALUATE 0
#define FLB_AWS_IMDS_VERSION_1 1
#define FLB_AWS_IMDS_VERSION_2 2

/* The following metadata paths can be evaluated with flb_aws_imds_request
* to retrieve specific metadata members */
#define FLB_AWS_IMDS_INSTANCE_ID_PATH "/latest/meta-data/instance-id/"
#define FLB_AWS_IMDS_AZ_PATH "/latest/meta-data/placement/availability-zone/"
#define FLB_AWS_IMDS_INSTANCE_TYPE_PATH "/latest/meta-data/instance-type/"
#define FLB_AWS_IMDS_PRIVATE_IP_PATH "/latest/meta-data/local-ipv4/"
#define FLB_AWS_IMDS_VPC_ID_PATH_PREFIX "/latest/meta-data/network/interfaces/macs/"
#define FLB_AWS_IMDS_AMI_ID_PATH "/latest/meta-data/ami-id/"
#define FLB_AWS_IMDS_ACCOUNT_ID_PATH "/latest/dynamic/instance-identity/document/"
#define FLB_AWS_IMDS_HOSTNAME_PATH "/latest/meta-data/hostname/"
#define FLB_AWS_IMDS_MAC_PATH "/latest/meta-data/mac/"
#define FLB_AWS_IMDS_INSTANCE_ID_PATH "/latest/meta-data/instance-id/"
#define FLB_AWS_IMDS_AZ_PATH "/latest/meta-data/placement/availability-zone/"
#define FLB_AWS_IMDS_INSTANCE_TYPE_PATH "/latest/meta-data/instance-type/"
#define FLB_AWS_IMDS_PRIVATE_IP_PATH "/latest/meta-data/local-ipv4/"
#define FLB_AWS_IMDS_VPC_ID_PATH_PREFIX "/latest/meta-data/network/interfaces/macs/"
#define FLB_AWS_IMDS_AMI_ID_PATH "/latest/meta-data/ami-id/"
#define FLB_AWS_IMDS_ACCOUNT_ID_PATH "/latest/dynamic/instance-identity/document/"
#define FLB_AWS_IMDS_HOSTNAME_PATH "/latest/meta-data/hostname/"
#define FLB_AWS_IMDS_MAC_PATH "/latest/meta-data/mac/"

#include <fluent-bit/flb_config.h>
#include <fluent-bit/flb_sds.h>

/* IMDS config values */
struct flb_aws_imds_config {
Expand All @@ -58,7 +61,7 @@ struct flb_aws_imds {
flb_sds_t imds_v2_token;
size_t imds_v2_token_len;

/*
/*
* Plugin can use EC2 metadata v1 or v2; default is FLB_AWS_IMDS_VERSION_EVALUATE
* which is evaluated to FLB_AWS_IMDS_VERSION_1 or FLB_AWS_IMDS_VERSION_2 when
* the IMDS is used.
Expand All @@ -72,9 +75,8 @@ struct flb_aws_imds {
* Note: Setting the FLB_IO_ASYNC flag is the job of the client.
* Flag Set Example: flags &= ~(FLB_IO_ASYNC)
*/
struct flb_aws_imds *flb_aws_imds_create(struct flb_config *config,
struct flb_aws_imds_config *imds_config,
struct flb_aws_client *ec2_imds_client);
struct flb_aws_imds *flb_aws_imds_create(const struct flb_aws_imds_config *imds_config,
struct flb_aws_client *ec2_imds_client);

/*
* Destroy IMDS context
Expand All @@ -85,19 +87,22 @@ void flb_aws_imds_destroy(struct flb_aws_imds *ctx);

/*
* Get IMDS metadata.
* Sets flb_sds_t metadata string to the value found at IMDS' metadata_path.
* Returns -1 on error, 0 on success.
*/
int flb_aws_imds_request(struct flb_aws_imds *ctx, char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len);
int flb_aws_imds_request(struct flb_aws_imds *ctx, const char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len);

/*
* Get IMDS metadata by key
* Expects metadata to be in a json object format.
* Returns NULL if key not found.
* Returns the full metadata value if key is NULL.
* Sets flb_sds_t metadata string to the value associated with provided key.
* Sets flb_sds_t metadata string to "NULL" if key not found.
* Sets flb_sds_t metadata string to the full metadata value if key is NULL.
* Returns -1 on error, 0 on success.
*/
int flb_aws_imds_request_by_key(struct flb_aws_imds *ctx, char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len, char *key);

int flb_aws_imds_request_by_key(struct flb_aws_imds *ctx, const char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len, char *key);

/*
* Get VPC id from EC2 IMDS. Requires multiple IMDS requests.
Expand Down
4 changes: 2 additions & 2 deletions src/aws/flb_aws_credentials_ec2.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ struct flb_aws_provider *flb_ec2_provider_create(struct flb_config *config,
implementation->client->upstream = upstream;

/* Use default imds configuration */
struct flb_aws_imds_config imds_config = flb_aws_imds_config_default;
implementation->imds_interface = flb_aws_imds_create(config, &imds_config, implementation->client);
implementation->imds_interface = flb_aws_imds_create(&flb_aws_imds_config_default,
implementation->client);
if (!implementation->imds_interface) {
flb_aws_provider_destroy(provider);
flb_error("[aws_credentials] EC2 IMDS configuration error");
Expand Down
124 changes: 59 additions & 65 deletions src/aws/flb_aws_imds.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,30 @@
* limitations under the License.
*/

#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_sds.h>
#include <fluent-bit/flb_http_client.h>
#include <fluent-bit/aws/flb_aws_imds.h>
#include <fluent-bit/flb_aws_credentials.h>
#include <fluent-bit/flb_aws_util.h>
#include <fluent-bit/flb_http_client.h>
#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_jsmn.h>
#include <fluent-bit/aws/flb_aws_imds.h>

#define FLB_AWS_IMDS_ROOT "/"
#define FLB_AWS_IMDS_V2_TOKEN_PATH "/latest/api/token"
#define FLB_AWS_IMDS_ROOT "/"
#define FLB_AWS_IMDS_V2_TOKEN_PATH "/latest/api/token"

/* Request headers */
static struct flb_aws_header imds_v2_token_ttl_header = {
.key = "X-aws-ec2-metadata-token-ttl-seconds",
.key_len = 36,
.val = "21600", // 6 hours (ie maximum ttl)
.val = "21600", // 6 hours (ie maximum ttl)
.val_len = 5,
};

/* Request header templates */
const static struct flb_aws_header imds_v2_token_token_header_template = {
.key = "X-aws-ec2-metadata-token",
.key_len = 24,
.val = "", // Replace with token value
.val_len = 0, // Replace with token length
.val = "", // Replace with token value
.val_len = 0, // Replace with token length
};

/* Declarations */
Expand All @@ -50,13 +49,11 @@ static int refresh_imds_v2_token(struct flb_aws_imds *ctx);

/* Default config values */
const struct flb_aws_imds_config flb_aws_imds_config_default = {
FLB_AWS_IMDS_VERSION_EVALUATE
};
FLB_AWS_IMDS_VERSION_EVALUATE};

/* Create IMDS context */
struct flb_aws_imds *flb_aws_imds_create(struct flb_config *config,
struct flb_aws_imds_config *imds_config,
struct flb_aws_client *ec2_imds_client)
struct flb_aws_imds *flb_aws_imds_create(const struct flb_aws_imds_config *imds_config,
struct flb_aws_client *ec2_imds_client)
{
struct flb_aws_imds *ctx = NULL;

Expand All @@ -67,7 +64,7 @@ struct flb_aws_imds *flb_aws_imds_create(struct flb_config *config,
return NULL;
}

/*
/*
* Set IMDS version to whatever is specified in config
* Version may be evaluated later if set to FLB_AWS_IMDS_VERSION_EVALUATE
*/
Expand All @@ -76,33 +73,32 @@ struct flb_aws_imds *flb_aws_imds_create(struct flb_config *config,

/* Detect IMDS support */
if (!ec2_imds_client->upstream) {
flb_debug("[imds] unable to connect to EC2 IMDS. ec2_imds_client upstream is null");
flb_debug(
"[imds] unable to connect to EC2 IMDS. ec2_imds_client upstream is null");

flb_free(ctx);
flb_aws_imds_destroy(ctx);
return NULL;
}
if (0 != strncmp(ec2_imds_client->upstream->tcp_host,
FLB_AWS_IMDS_HOST,
FLB_AWS_IMDS_HOST_LEN)) {
flb_debug("[imds] ec2_imds_client tcp host must be set to %s",
FLB_AWS_IMDS_HOST);
flb_free(ctx);
if (0 != strncmp(ec2_imds_client->upstream->tcp_host, FLB_AWS_IMDS_HOST,
FLB_AWS_IMDS_HOST_LEN)) {
flb_debug("[imds] ec2_imds_client tcp host must be set to %s", FLB_AWS_IMDS_HOST);
flb_aws_imds_destroy(ctx);
return NULL;
}
if (ec2_imds_client->upstream->tcp_port != FLB_AWS_IMDS_PORT) {
flb_debug("[imds] ec2_imds_client tcp port must be set to %i",
FLB_AWS_IMDS_PORT);
flb_free(ctx);
flb_debug("[imds] ec2_imds_client tcp port must be set to %i", FLB_AWS_IMDS_PORT);
flb_aws_imds_destroy(ctx);
return NULL;
}

/* Connect client */
ctx->ec2_imds_client = ec2_imds_client;
return ctx;
}

/* Destroy IMDS context */
void flb_aws_imds_destroy(struct flb_aws_imds *ctx) {
void flb_aws_imds_destroy(struct flb_aws_imds *ctx)
{
if (ctx->imds_v2_token) {
flb_sds_destroy(ctx->imds_v2_token);
}
Expand All @@ -111,21 +107,19 @@ void flb_aws_imds_destroy(struct flb_aws_imds *ctx) {
}

/* Get IMDS metadata */
int flb_aws_imds_request(struct flb_aws_imds *ctx, char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len)
int flb_aws_imds_request(struct flb_aws_imds *ctx, const char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len)
{
return flb_aws_imds_request_by_key(ctx, metadata_path, metadata,
metadata_len, NULL);
return flb_aws_imds_request_by_key(ctx, metadata_path, metadata, metadata_len, NULL);
}

/* Get IMDS metadata by key */
int flb_aws_imds_request_by_key(struct flb_aws_imds *ctx, char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len,
char *key)
int flb_aws_imds_request_by_key(struct flb_aws_imds *ctx, const char *metadata_path,
flb_sds_t *metadata, size_t *metadata_len, char *key)
{
int ret;
flb_sds_t tmp;

struct flb_http_client *c = NULL;

struct flb_aws_client *ec2_imds_client = ctx->ec2_imds_client;
Expand All @@ -145,14 +139,14 @@ int flb_aws_imds_request_by_key(struct flb_aws_imds *ctx, char *metadata_path,
token_header.val = ctx->imds_v2_token;
token_header.val_len = ctx->imds_v2_token_len;
flb_debug("[imds] using IMDSv2");
} else {
}
else {
flb_debug("[imds] using IMDSv1");
}

c = ec2_imds_client->client_vtable->request(ec2_imds_client, FLB_HTTP_GET,
metadata_path, NULL, 0,
&token_header,
(imds_version == FLB_AWS_IMDS_VERSION_1) ? 0 : 1);
c = ec2_imds_client->client_vtable->request(
ec2_imds_client, FLB_HTTP_GET, metadata_path, NULL, 0, &token_header,
(imds_version == FLB_AWS_IMDS_VERSION_1) ? 0 : 1);
if (!c) {
return -1;
}
Expand All @@ -175,29 +169,27 @@ int flb_aws_imds_request_by_key(struct flb_aws_imds *ctx, char *metadata_path,
token_header.val = ctx->imds_v2_token;
token_header.val_len = ctx->imds_v2_token_len;
flb_debug("[imds] refreshed IMDSv2 token");
c = ec2_imds_client->client_vtable->request(ec2_imds_client, FLB_HTTP_GET,
metadata_path, NULL, 0,
&token_header, 1);
c = ec2_imds_client->client_vtable->request(
ec2_imds_client, FLB_HTTP_GET, metadata_path, NULL, 0, &token_header, 1);
}

if (c->resp.status != 200) {
if (c->resp.payload_size > 0) {
flb_debug("[imds] metadata request failure response\n%s",
c->resp.payload);
flb_debug("[imds] metadata request failure response\n%s", c->resp.payload);
}
flb_http_client_destroy(c);
return -1;
}

if (key != NULL) {
/* get the value of the key from payload json string */
tmp = flb_json_get_val(c->resp.payload,
c->resp.payload_size, key);
tmp = flb_json_get_val(c->resp.payload, c->resp.payload_size, key);
if (!tmp) {
tmp = flb_sds_create_len("NULL", 4);
flb_error("[imds] %s is undefined in EC2 instance", key);
}
} else {
}
else {
tmp = flb_sds_create_len(c->resp.payload, c->resp.payload_size);
}

Expand Down Expand Up @@ -231,13 +223,14 @@ flb_sds_t flb_aws_imds_get_vpc_id(struct flb_aws_imds *ctx)
return NULL;
}

/* the VPC full path should be like:
/*
* the VPC full path should be like:
* latest/meta-data/network/interfaces/macs/{mac_id}/vpc-id/"
*/
flb_sds_t vpc_path = flb_sds_create_size(70);
vpc_path = flb_sds_printf(&vpc_path, "%s/%s/%s/",
"/latest/meta-data/network/interfaces/macs",
mac_id, "vpc-id");
vpc_path =
flb_sds_printf(&vpc_path, "%s/%s/%s/",
"/latest/meta-data/network/interfaces/macs", mac_id, "vpc-id");
ret = flb_aws_imds_request(ctx, vpc_path, &vpc_id, &vpc_id_len);

flb_sds_destroy(mac_id);
Expand All @@ -247,26 +240,28 @@ flb_sds_t flb_aws_imds_get_vpc_id(struct flb_aws_imds *ctx)
}

/* Obtain the IMDS version */
static int get_imds_version(struct flb_aws_imds *ctx) {
static int get_imds_version(struct flb_aws_imds *ctx)
{
struct flb_aws_client *client = ctx->ec2_imds_client;
struct flb_aws_header invalid_token_header;
struct flb_http_client *c = NULL;

if (ctx->imds_version != FLB_AWS_IMDS_VERSION_EVALUATE) {
return ctx->imds_version;
}

/* Evaluate version
/*
* Evaluate version
* To evaluate wether IMDSv2 is available, send an invalid token
* in IMDS request. If response status is 'Unauthorized', then IMDSv2
* is available.
*/
struct flb_aws_header invalid_token_header = imds_v2_token_token_header_template;
invalid_token_header = imds_v2_token_token_header_template;
invalid_token_header.val = "INVALID";
invalid_token_header.val_len = 7;
c = client->client_vtable->request(client, FLB_HTTP_GET,
FLB_AWS_IMDS_ROOT, NULL, 0,
c = client->client_vtable->request(client, FLB_HTTP_GET, FLB_AWS_IMDS_ROOT, NULL, 0,
&invalid_token_header, 1);

if (!c) {
return FLB_AWS_IMDS_VERSION_EVALUATE;
}
Expand All @@ -277,7 +272,8 @@ static int get_imds_version(struct flb_aws_imds *ctx) {
refresh_imds_v2_token(ctx);
}

/* Success means that IMDS version 1 is in use
/*
* Success means that IMDS version 1 is in use
* (Not Tested, TODO: Must test this on an instance without IMDSv2)
*/
if (c->resp.status == 200) {
Expand All @@ -298,8 +294,8 @@ static int refresh_imds_v2_token(struct flb_aws_imds *ctx)
struct flb_aws_client *ec2_imds_client = ctx->ec2_imds_client;

c = ec2_imds_client->client_vtable->request(ec2_imds_client, FLB_HTTP_PUT,
FLB_AWS_IMDS_V2_TOKEN_PATH, NULL, 0,
&imds_v2_token_ttl_header, 1);
FLB_AWS_IMDS_V2_TOKEN_PATH, NULL, 0,
&imds_v2_token_ttl_header, 1);

if (!c) {
return -1;
Expand All @@ -317,12 +313,10 @@ static int refresh_imds_v2_token(struct flb_aws_imds *ctx)

/* Preserve token information in ctx */
if (c->resp.payload_size > 0) {

if (ctx->imds_v2_token) {
flb_sds_destroy(ctx->imds_v2_token);
}
ctx->imds_v2_token = flb_sds_create_len(c->resp.payload,
c->resp.payload_size);
ctx->imds_v2_token = flb_sds_create_len(c->resp.payload, c->resp.payload_size);
if (!ctx->imds_v2_token) {
flb_errno();
flb_http_client_destroy(c);
Expand Down
Loading

0 comments on commit fa844ec

Please sign in to comment.