K8s vulnerability CVE-2021-25735

3 min read読了の目安(約3200字

Vulnerability

CVE-2021-25735 is published. In some cases, user can bypass the validation of Validating Admission Webhook.

https://github.com/kubernetes/kubernetes/issues/100096

Concrete example

This example is a Validating Admission Webhook which checks a label at node updation.
This allows updation when the label editAllowed is true otherwise it denies.

var https = require('https');
var fs =  require('fs');

var options = {
  key: fs.readFileSync('/tls/tls.key'),
  cert: fs.readFileSync('/tls/tls.crt'),
  requestCert: false,
  rejectUnauthorized: false
};

var server = https.createServer(options);
server.on('request', doRequest);
server.listen(8080);
console.log('HTTPS Server running!');

function doRequest(req, res) {
  if (req.headers['content-type'] !== 'application/json') {
    console.log('content-type is not application/json:' + req.headers['content-type']);
    return
  }

  if (req.method !== 'POST') {
    console.log('method is not POST:' + req.method);
    return
  }

  var body = '';
  req.on('data', function(chunk) {
    body += chunk;
  });
  req.on('end', function() {
    const requestedAdmissionReview = JSON.parse(body);
    isAllowed = requestedAdmissionReview.request.oldObject.metadata.labels['editAllowed'] === 'true';

    responseAdmissionReview = {
      'apiVersion': 'admission.k8s.io/v1',
      'kind': 'AdmissionReview',
      'response': {
        'uid': requestedAdmissionReview.request.uid,
        'allowed': isAllowed,
        'status': {
          'message': (isAllowed ? 'Validation succeeded' : 'Validation failed')
        }
      }
    };

    res.writeHead(200, {'Content-Type': 'application/json'});
    res.write(JSON.stringify(responseAdmissionReview));
    res.write('\n');
    res.end();
  });
}

Now let's update a node by following command.

$ kubectl edit nodes nodename
...
  labels:
    editAllowed: "false"
...

We try to add a label dummy: dummy here.

  labels:
    dummy: dummy
    editAllowed: "false"

Ofcourse it results in error by Validating Admission Webhook.

error: nodes "nodename" could not be patched: admission webhook "sample-validating-webhook.hoge.fuga.local" denied the request: Validation failed
You can run `kubectl replace -f /tmp/kubectl-edit-9e91t.yaml` to try this update again.

What if we also change editAllowed to true?

  labels:
    dummy: dummy
    editAllowed: "true"

By the change, we can bypass the validation of Validating Admission Webhook and add dummy: dummy label.

Cause

kube-apiserver pass request.object and request.oldObject to Validating Admission Webhook. request.object contains new configs and request.oldObject contains old configs. The bug that overwrite a part of request.oldObject with ```request.object causes this issue.

Affected Operations and versions

If both conditions 1 and 2 are met, the system is affected by this vulnerability.

  1. Using Validating Admission Webhook for nodes
  2. Using Validating Admission Webhook with old values

Affected kube-apiserver versions

  • kube-apiserver v1.20.0 - v1.20.5
  • kube-apiserver v1.19.0 - v1.19.9
  • kube-apiserver <= v1.18.17