Terraform docs on provisioning explicitly indicates that it considers the use of creators for basic bootstrapping as a task only once and that it should not be used as a replacement for a proper configuration management tool such as Ansible:
Provisioners run only when the resource is created. They are not a replacement for configuration management and software changes already running the server, and instead, it simply means load the server. For configuration management, you must use Terraform Provision to invoke real configuration management solution.
and
If the resource is successfully created but not executed at the time of submission, Terraform will be an error and mark the resource as "corrupted". The resource that was corrupted was physically created, but cannot be considered safe to use, because the backup failed.
When you create your next execution plan, Terraform will delete all corrupted resources and create new resources, trying to secure again. It does not try to restart initialization on the same resource, because it is not guaranteed to be safe.
Terraform does not automatically roll back and destroy the resource during application when a failure occurs because it will happen against the execution plan: the execution plan would say the resource would be created, but did not say that it would ever be deleted. But if you create an execution plan with a corrupted resource, the plan will clearly state that the resource will be destroyed because it is corrupted.
Providing data is important for the ability to load instances. In the form of another reminder, this is not a replacement for configuration management. It is designed for just boot machines. If you use configuration management, you should use software as a way to download the configuration management utility.
Let's consider the creators as similar to the user data of the EC2 script, since it only works once at creation, and if it fails, you need to destroy the instance and try again.
The advantage of this is that Terraform does not need any knowledge on how to make idempotent changes in the operating system, since Terraform operates at a level higher than the instance itself and more when providing the entire data center.
If you need more flexibility than this, consider either using Terraform to invoke the configuration management system to provide the instance correctly (and then allowing it to retry if it fails, disconnect from the Terraform preparation stage), or use an orchestration tool like Jenkins to wrap both Terraform and an alternative configuration management tool such as Ansible.
Another option is to go further along the route of immutable infrastructure and use Packer to create AMI using Ansible or another tool and then just use Terraform to deploy AMI, as this does not require further provision of the instance.