zncdatadev / secret-operator

Operator to provision and inject secrets for Kubernetes pods
Apache License 2.0
2 stars 3 forks source link

[Draft]: pod restart annotation name conflict vulnerability #115

Open whg517 opened 1 month ago

whg517 commented 1 month ago

background

After the pod uses tls to assign the certificate, secret-csi updates the expiration time of the certificate to the pod annotation. commons-operator's pod-restarter coordinator deletes the pod when it detects that time has expired. The workload controller automatically creates new Pods, and the corresponding tls is regenerated.

desc

The current implementation of the expiration time storage policy is to set the expiration time in the tls volume pod annotation, the key value of the annotation is restarter.zncdata.dev/expires-at.<volume hash>. The policy is to remove the 16-bit length of secrets.zncdata.dev/volume: and volumeID after sha256, then take the first 16 digits

Since the k8s annotation key length is 63, the above strategy is adopted to ensure the readability of the key value and its correlation with the volume. But that led to a crash hole.


// updatePod updates the pod annotation with the secret expiration time.
// The volume ID is hashed using sha256, and the first 16 bytes are used as the volume tag.
// Then, the expiration time is written to the pod annotation with the key "secrets.zncdata.dev/restarter-expires-at:<volume_tag>".
//
// Considering the length limitation of Kubernetes annotations, we hash the volume ID to maintain the readability of the annotation
// and its association with the volume. However, truncating the hash to the first 16 bytes may introduce collision risks.
func (n *NodeServer) updatePod(ctx context.Context, pod *corev1.Pod, volume_id string, expiresTime *time.Time) error {
    if pod.Annotations == nil {
        pod.Annotations = make(map[string]string)
    }
    patch := client.MergeFrom(pod.DeepCopy())
    if expiresTime == nil {
        logger.V(5).Info("Expiration time is nil, skip update pod annotation", "pod", pod.Name)
        return nil
    }

    volume_tag_hash := sha256.New()
    volume_tag_hash.Write([]byte("secrets.zncdata.dev/volume:"))
    volume_tag_hash.Write([]byte(volume_id))
    volume_tag := volume_tag_hash.Sum(nil)
    // get 16 bytes of volume tag, but it maybe cause collision vulnerability
    volume_tag = volume_tag[:16]

    annotationexpiresName := constants.PrefixLabelRestarterExpiresAt + string(volume_tag)
    expiresTimeStr := expiresTime.Format(time.RFC3339)

    pod.Annotations[annotationexpiresName] = expiresTimeStr

    if err := n.client.Patch(ctx, pod, patch); err != nil {
        return err
    }
    logger.V(5).Info("Pod patched", "pod", pod.Name)
    return nil
}

suggest

whg517 commented 1 month ago

@lwpk110 @tutunannan please review it