Unable to create a new Kubanetes deployment using node 'kubernetes-client' - deployment

const k8s = require('kubernetes-client');
const endpoint = 'https://' + IP;
const ext = new k8s.Extensions({
url: endpoint,
version: 'v1beta1',
insecureSkipTlsVerify: true,
namespace,
auth: {
bearer: token,
},
});
const body = {
spec: {
template: {
spec: {
metadata: [{
name,
image,
}]
}
}
}
};
ext.namespaces.deployments(name).put({body}, (err, response => { console.log(response); })
The above functions seem to authenticate with GET and PUSH, however I get the following error message when using POST.
the server does not allow this method on the requested resource
Blockquote

I think the problem might be, that due to changes of Kubernetes 1.6 to RCAB your pod has not the right privileges to schedule pods, get logs, ... through the API server.
Make sure you are using the admin.conf kubeconfig.
But be aware that giving the node cluster admin permissions sets anyone who can access the node to cluster admin ;)

Related

Keycloak Step Up from Client

The Keycloak documentation here says you need to add ACR with claims in the request in order to do authentication step up to a higher level. But how is this accomplished from either the keycloak.js client library, or the keycloak-js npm client library?
So basically, how do you get the following claims query param to be passed?
https://{DOMAIN}/realms/{REALMNAME}/protocol/openid-connect/auth?client_id={CLIENT-ID}&redirect_uri={REDIRECT-URI}&scope=openid&response_type=code&response_mode=query&nonce=exg16fxdjcu&claims=%7B%22id_token%22%3A%7B%22acr%22%3A%7B%22essential%22%3Atrue%2C%22values%22%3A%5B%22gold%22%5D%7D%7D%7D
The format of the claims is like this as seen in the documentation:
claims= {
"id_token": {
"acr": {
"essential": true,
"values": ["gold"]
}
}
}
Doing this off the top of my head, but I think this should do it.
const keycloak = Keycloak({
url: {DOMAIN},
realm: {REALMNAME},
clientId: {CLIENT-ID}
});
keycloak.login({
... your login options
acr: { values: ["silver", "gold"], essential: true }
})
The adapter will take the acr option and apply it to claims.id_token

Programmatically issuing a Kubernetes certificate

I was able to manually create a certificate:
I created a csr file
I created and applied a CertificateSigningRequest k8s resource
I approved the request using
kubectl certificate approve <name>
I extracted the certificate from the CertificateSigningRequest's status.certificate field.
Now I want to repeat the process programmatically. I'm using the #kubernetes/client-node npm package for this purpose.
I'm able to create and apply the CertificateSigningRequest resource:
const csrResource = await adminCertApi.createCertificateSigningRequest({
metadata: {
name: 'my.email#my.company.com',
},
spec: {
request: csrBase64,
signerName: 'kubernetes.io/kube-apiserver-client',
usages: [
'client auth'
],
},
});
But then I get stuck trying to approve the request (trying to follow the documentation). I tried several variations that look like this:
csrResource.body.status.conditions = [
{
message: 'Approved by CWAdmin GraphQL Lambda function',
reason: 'ApprovedByCWAdmin',
type: 'Approved',
}
];
const response = await adminCertApi.patchCertificateSigningRequest('my.email#my.company.com', csrResource.body, undefined, undefined, undefined, undefined, { headers: { 'Content-Type': 'application/strategic-merge-patch+json' } });
Unfortunately, this does not update the status.conditions field. Even if it did, what triggers the signing of the certificate? The documentation states that the kube-controller-manager never auto-approves requests of type kubernetes.io/kube-apiserver-client.
In other words, what is the programmatic equivalent of kubectl certificate approve?
I found this bit of documentation that helped me solve the issue:
status is required and must be True, False, or Unknown
Approved/Denied conditions can only be set via the /approval subresource
So I added the status field to the condition and changed the API call to patchCertificateSigningRequestApproval.
The working code now looks like this:
const body = {
status: {
conditions: [
{
message: 'Approved by CWAdmin GraphQL Lambda function',
reason: 'ApprovedByCWAdmin',
type: 'Approved',
status: 'True',
}
]
}
};
const response = await adminCertApi.patchCertificateSigningRequestApproval('my.email#my.company.com', body, undefined, undefined, undefined, undefined, { headers: { 'Content-Type': 'application/strategic-merge-patch+json' } });

Circular dependency of defining APIGateway, ARecord, and Certificate

In CDK, I would like to define:
An APIGateway (backed by a Lambda)
An ARecord to resolve to the APIGateway
A Certificate associated with the ARecord
The code to do this would look something like:
let apig = new LambdaRestApi(this, 'api', {
handler: <some Lambda Function>,
proxy: true,
deploy: true,
domainName: {
domainName: aRecord.domainName,
certificate: cert
}
})
let aRecord = new ARecord(this, 'apiDNS', {
zone: zone,
recordName: props.recordName,
target: RecordTarget.fromAlias(new ApiGateway(apig))
})
let cert = new Certificate(this, 'cert', {
domainName: aRecord.domainName,
validation: CertificateValidation.fromDns(zone)
});
However, this appears to be impossible because of circular dependencies:
The APIGateway needs to have a domain name set at construction-time (there's an .addDomainName method, but even when that is called, I still get an error API does not define a default domain name when trying to call RecordTarget.fromAlias(...)), which requires that both the Certificate and the ARecord exist.
The ARecord needs to have a target, which requires that the ApiGateway exists.
The Certificate needs to have a DomainName set, which requires that the ARecord exists
I guess I could manually determine what the ARecord's domainName would be, and set that as the domainName for the Certificate and the APIGateway - but that feels like I'm doing something wrong. Is there a way to "lazily" set the APIGateway's domainName to "the domainName of the ARecord (that hasn't been created yet)?", or some other way to achieve this setup with explicit (rather than implicit) associations?
As already mentioned in ticket, it is not possible for CDK or CloudFormation to create resource which depends on each other.
Here is blog on Circular Dependency
Resource A is dependent on Resource B, and Resource B is dependent on
Resource A. When AWS CloudFormation assesses that this type of
condition exists, you will get a circular dependency error because AWS
CloudFormation is unable to clearly determine which resource should be
created first.
In this case, we can create a ACM Certificate for subDomain and then pass the domain and certificate to LambdaRestApi.
Here is the modified CDK.
const rootDomain = "mydomain.com";
const subDomain = "api-test";
const zone = route53.HostedZone.fromLookup(this, "baseZone", {
domainName: rootDomain,
});
let cert = new acm.Certificate(this, "cert", {
domainName: `${subDomain}.${rootDomain}`,
validation: acm.CertificateValidation.fromDns(zone),
});
const backend = new lambda.Function(this, "MyLayeredLambda", {
code: new lambda.InlineCode("foo"),
handler: "index.handler",
runtime: lambda.Runtime.NODEJS_10_X,
});
const restApi = new apigw.LambdaRestApi(this, "myapi", {
handler: backend,
domainName: {
domainName: `${subDomain}.${rootDomain}`,
certificate: cert,
endpointType: apigw.EndpointType.REGIONAL,
},
});
new route53.ARecord(this, "apiDNS", {
zone: zone,
recordName: `${subDomain}`,
target: route53.RecordTarget.fromAlias(
new route53Targets.ApiGateway(restApi)
),
});
}

How can I refer to the generated domain name of `elasticsearch.CfnDomain` in AWS CDK?

I created a CfnDomain in AWS CDK and I was trying to get the generated domain name to create an alarm.
const es = new elasticsearch.CfnDomain(this, id, esProps);
new cloudwatch.CfnAlarm(this, "test", {
...
dimensions: [
{
name: "DomainName",
value: es.domainName,
},
],
});
But it seems that the domainName attribute is actually the argument that I pass in (I passed none so it will be autogenerated), so it's actually undefined and can't be used.
Is there any way that I can specify it such that it will wait for the elasticsearch cluster to be created so that I can obtain the generated domain name, or is there any other way to created an alarm for the metrics of the cluster?
You use CfnDomain.ref as the domain value for your dimension. Sample alarm creation for red cluster status:
const domain: CfnDomain = ...;
const elasticDimension = {
"DomainName": domain.ref,
};
const metricRed = new Metric({
namespace: "AWS/ES",
metricName: "ClusterStatus.red",
statistic: "maximum",
period: Duration.minutes(1),
dimensions: elasticDimension
});
const redAlarm = metricRed.createAlarm(construct, "esRedAlarm", {
alarmName: "esRedAlarm",
evaluationPeriods: 1,
threshold: 1
});

Why isn't my Firebase app connecting to Google Secret Manager?

I can't figure out why I keep getting the error: Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
firebase login from my command line returns that I am already logged in and
I have configured my-app#appspot.gserviceaccount.com to be a Secret Manager Secret Accessor in the GCP IAM admin dashboard within the same project.
Here's the code I'm using:
const { SecretManagerServiceClient } = require("#google-cloud/secret-manager");
const client = new SecretManagerServiceClient();
const gcpSecretsLoader = async (secretName: string) => {
try {
const secret = await client.accessSecretVersion({
name: `projects/my-app/secrets/${secretName}/versions/latest`,
});
const payload = secret.payload.data.toString("utf8");
console.info(`Payload: ${payload}`);
} catch (err) {
console.log(err);
}
};
gcpSecretsLoader("CLIENT_ID"); // CLIENT_ID matched a secret name within the secret manager