https://pulumi.com logo
Title
b

busy-journalist-6936

07/21/2021, 11:43 PM
Typescript EKS IaC & CI/CD pipeline in progress. I think that I want to take the kubeconfig output and push that to an s3 bucket that I've added to my index.ts Willing to hear alternative suggestions for where/how to output that kubeconfig. Presuming I continue with this course of action, are there examples of this kind of thing? Taking a resulting output and saving it to file on an s3 that I can learn from?
b

bored-table-20691

07/22/2021, 12:05 AM
We do a similar-ish thing in Go using the Automation API (we don’t push a kubeconfig, but other parts of the stack output).
b

busy-journalist-6936

07/22/2021, 3:31 AM
interesting
I'm getting closer, but my limited programming language knowledge is leaving me stumped:
const keksAdminBucket = new aws.s3.Bucket("keksAdminBucket", {acl: "private"});
const keksAdminBucketObject = new aws.s3.BucketObject("keksAdminBucketObject", {
    key: "kubeconfig",
    bucket: keksAdminBucket.id,
    source: new pulumi.asset.StringAsset(cluster.kubeconfig),
    serverSideEncryption: "aws:kms",
});
getting closer
const keksAdminBucket = new aws.s3.Bucket("keksAdminBucket", {acl: "private"});
const keksAdminBucketObject = new aws.s3.BucketObject("keksAdminBucketObject", {
    key: "kubeconfig",
    bucket: keksAdminBucket.id,
    source: new pulumi.asset.StringAsset(String(cluster.kubeconfig)),
    serverSideEncryption: "aws:kms",
});
yep, ending today's battle with these kinds of errors:
index.ts(45,42): error TS2345: Argument of type 'Output<any>' is not assignable to parameter of type 'string | Promise<string>'.
      Type 'OutputInstance<any>' is not assignable to type 'string | Promise<string>'.
        Type 'OutputInstance<any>' is missing the following properties from type 'Promise<string>': then, catch, [Symbol.toStringTag], finally
s

steep-toddler-94095

07/22/2021, 6:52 AM
cluster.kubeconfig
is type
Output<any>
but
StringAsset
takes in a
string
or
Promise<string>
. Your problem is that of incompatible types. One way to solve this is:
const keksAdminBucketObject = eksCluster.kubeconfig.apply(
  (config) =>
    new BucketObject("keksAdminBucketObject", {
      key: "kubeconfig",
      bucket: keksAdminBucket.id,
      source: new StringAsset(config),
      serverSideEncryption: "aws:kms",
    })
)
by calling
apply
on
kubeconfig
, you are able to interact with its value as a
string
instead of
Output<string>
within the callback function (with the
config
variable). The caveat now is that
keksAdminBucketObject
becomes a
Output<BucketObject>
instead of a
BucketObject
so if you ever want to reference values from
keksAdminBucketObject
you'll need to do the same
apply
trick. It's generally not advised to create cloud resources within an
apply
, but sometimes it's sort of the only way. In your case, I don't know of a better way to do it.
One question I have though is why you want the kubeconfig contents in an S3 bucket. What are you trying to achieve here? With EKS you are able to map IAM users/roles to Kubernetes roles. If you are trying to give a CI user admin to the cluster, I'd recommend going that route instead.
b

busy-journalist-6936

07/22/2021, 2:30 PM
To answer the logical question, you are right, this isnt an advanced implementation yet. I'm admittedly catching up to the 101 level. OIDC enabled is the plan for the near future but this is primarily to hand off to a customer and we're going to iteratively improve as we go. Kubeconfig for now is for human consumption.
const keksAdminBucket = new aws.s3.Bucket("keksAdminBucket")
const keksAdminBucketObject = cluster.kubeconfig.apply(
  (config) =>
    new aws.s3.BucketObject("keksAdminBucketObject", {
      key: "kubeconfig",
      bucket: keksAdminBucket.id,
      source: new pulumi.asset.StringAsset(config),
      serverSideEncryption: "aws:kms",
    })
)
And for the technical question, I took your example, adjusted for a few errors, and now I'm down to this one:
pulumi:pulumi:Stack KongOnEKS-KongOnEKS running error: Error: failed to register new resource keksAdminBucketObject [aws:s3/bucketObject:BucketObject]: 2 UNKNOWN: unexpected asset text of type map[string]interface {}
Is this supposed to be a closer approximation to something that might work?
const keksAdminBucket = new aws.s3.Bucket("keksAdminBucket", {acl: "private"});
const keksAdminBucketObject = new aws.s3.BucketObject("keksAdminBucketObject", {
    key: "kubeconfig",
    bucket: keksAdminBucket.id,
    source: cluster.kubeconfig.apply(s => new pulumi.asset.StringAsset(String(s))),
    serverSideEncryption: "aws:kms",
});
s

steep-toddler-94095

07/22/2021, 4:45 PM
I incorrectly thought
config
was a
string
, but it's actually an
Object
. Use the same code I gave you, but change the
source
line to
source: new StringAsset(JSON.stringify(config)),
b

busy-journalist-6936

07/22/2021, 4:46 PM
ah, i was playing with JSON.stringify yesterday. let me try your suggestion
OMG THAT MADE MY DAY!!!
😄 1
const keksAdminBucket = new aws.s3.Bucket("keksAdminBucket", {acl: "private"});
const keksAdminBucketObject = cluster.kubeconfig.apply(
  (config) =>
    new aws.s3.BucketObject("keksAdminBucketObject", {
      key: "kubeconfig",
      bucket: keksAdminBucket.id,
      source: new pulumi.asset.StringAsset(JSON.stringify(config)),
      serverSideEncryption: "aws:kms",
    })
)
That's the magic right there.
Thank you @steep-toddler-94095
👍 1